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/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/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-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/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 d601f34990264..c64def30e833b 100644 --- a/docs/Language Feature Status.md +++ b/docs/Language Feature Status.md @@ -13,7 +13,8 @@ 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) | [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) | [In Progress](https://github.com/dotnet/roslyn/issues/55306) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [jcouv](https://github.com/jcouv) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | +| [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) | @@ -23,10 +24,11 @@ efforts behind them. | [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) | | [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) | -| [Cache delegates for static method group](https://github.com/dotnet/roslyn/issues/5835) | main | [In Progress](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) | -| [Switch on ReadOnlySpan](https://github.com/dotnet/csharplang/issues/1881) | main | [In Progress](https://github.com/dotnet/roslyn/pull/44388) | [YairHalberstadt ](https://github.com/YairHalberstadt) | [cston](https://github.com/cston), [RikkiGibson](https://github.com/RikkiGibson) | [jcouv](https://github.com/jcouv) | -| [nameof accessing instance memebers](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) | +| [Switch on ReadOnlySpan](https://github.com/dotnet/csharplang/issues/1881) | main | [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) | TBD | [In Progress](https://github.com/dotnet/roslyn/issues/59196) | TBD | TBD | [AlekseyTs](https://github.com/AlekseyTs) | # C# 10.0 diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md index 1c5bd04f9a240..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; 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/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/eng/Version.Details.xml b/eng/Version.Details.xml index 17d6542bdc20c..646f210ed6971 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -13,18 +13,18 @@ - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + 4d6406fa2e84c8516a338694be3a4097e6e1f104 - + https://github.com/dotnet/roslyn - cc0d213b15fdda217ad888d269d19754fa556eb4 + 592501cbb9c9394072a245c15b3458ff88155d85 - + https://github.com/dotnet/arcade - 9ffc76ac9f5799de9b28ee59f9bfbe0f8844d0d7 + 4d6406fa2e84c8516a338694be3a4097e6e1f104 diff --git a/eng/Versions.props b/eng/Versions.props index 58ad1940a148c..39a186423864c 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -8,20 +8,20 @@ 4 2 0 - 1 + 2 $(MajorVersion).$(MinorVersion).$(PatchVersion) $(MajorVersion).$(MinorVersion).0.0 - 4.1.0-3.22062.11 + 4.1.0-3.22075.3 3.3.3-beta1.21105.3 6.0.0-rc1.21366.2 - 1.1.1-beta1.21480.3 + 1.1.1-beta1.22081.4 0.1.122-beta 4.0.1 @@ -29,7 +29,7 @@ 17.0.487 5.0.0-alpha1.19409.1 5.0.0-preview.1.20112.8 - 17.1.3 + 17.1.8 17.0.31723.112 16.5.0 - 4.7.0 - 5.0.0 + 6.0.0 + 6.0.0 4.5.0 4.5.4 @@ -266,14 +266,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/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/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/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/jobs.yml b/eng/common/templates/jobs/jobs.yml index ff4ab75c886dc..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,7 +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 }} 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 8985b429c8543..2f176571f020c 100644 --- a/eng/common/templates/post-build/post-build.yml +++ b/eng/common/templates/post-build/post-build.yml @@ -90,25 +90,25 @@ stages: variables: - template: common-variables.yml jobs: - - template: setup-maestro-vars.yml - parameters: - BARBuildId: ${{ parameters.BARBuildId }} - PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }} - - 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: @@ -129,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: @@ -186,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: @@ -224,7 +230,6 @@ 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 }} @@ -239,21 +244,26 @@ stages: 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' + # 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: 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/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 14499e77c8539..ba60c0fb18e4a 100644 --- a/eng/config/PublishData.json +++ b/eng/config/PublishData.json @@ -210,21 +210,32 @@ "channels": [], "vsBranch": "rel/d17.1", "vsMajorVersion": 17, - "insertionCreateDraftPR": false, - "insertionTitlePrefix": "[d17.1p3]" + "insertionTitlePrefix": "[d17.1]" + }, + "release/dev17.2": { + "nugetKind": [ + "Shipping", + "NonShipping" + ], + "version": "4.2.*", + "packageFeeds": "default", + "channels": [], + "vsBranch": "main", + "vsMajorVersion": 17, + "insertionTitlePrefix": "[d17.2p1]" }, "main": { "nugetKind": [ "Shipping", "NonShipping" ], - "version": "4.1.*", + "version": "4.2.*", "packageFeeds": "default", "channels": [], "vsBranch": "main", "vsMajorVersion": 17, "insertionCreateDraftPR": false, - "insertionTitlePrefix": "[d17.2p1]" + "insertionTitlePrefix": "[d17.2p2]" }, "features/NullableReferenceTypes": { "nugetKind": "PerBuildPreRelease", diff --git a/eng/test-determinism.ps1 b/eng/test-determinism.ps1 index e7c36de72ba8d..c98e405ff4fdf 100644 --- a/eng/test-determinism.ps1 +++ b/eng/test-determinism.ps1 @@ -24,8 +24,12 @@ if ($help) { # makes them non-deterministic. $script:skipList = @( # Added to work around https://github.com/dotnet/roslyn/issues/48417 - "Microsoft.CodeAnalysis.EditorFeatures2.UnitTests.dll" + "Microsoft.CodeAnalysis.EditorFeatures2.UnitTests.dll", + + # Work around XLF issues https://github.com/dotnet/roslyn/issues/58840 + "Roslyn.VisualStudio.DiagnosticsWindow.dll.key" ) + function Run-Build([string]$rootDir, [string]$logFileName) { # Clean out the previous run @@ -79,7 +83,7 @@ function Get-BinDir([string]$rootDir) { # directory. function Get-FilesToProcess([string]$rootDir) { $objDir = Get-ObjDir $rootDir - foreach ($item in Get-ChildItem -re -in *.dll,*.exe,*.pdb,*.sourcelink.json $objDir) { + foreach ($item in Get-ChildItem -re -in *.dll,*.exe,*.pdb,*.sourcelink.json,*.key $objDir) { $filePath = $item.FullName $fileName = Split-Path -leaf $filePath $relativeDirectory = Split-Path -parent $filePath diff --git a/global.json b/global.json index 3b4f034197c04..8b4d21042c9d0 100644 --- a/global.json +++ b/global.json @@ -12,7 +12,7 @@ "xcopy-msbuild": "16.10.0-preview2" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.22068.3", - "Microsoft.DotNet.Helix.Sdk": "7.0.0-beta.22068.3" + "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.22080.1", + "Microsoft.DotNet.Helix.Sdk": "7.0.0-beta.22080.1" } } diff --git a/scripts/merge-vs-deps.ps1 b/scripts/merge-vs-deps.ps1 index 292cb41837ba4..3352de407b318 100644 --- a/scripts/merge-vs-deps.ps1 +++ b/scripts/merge-vs-deps.ps1 @@ -15,6 +15,6 @@ else { if (-not $?) { - Write-Host "##vso[task.logissue type=error]Failed to merge main-vs-deps into source branch" - exit 1 + Write-Host "##vso[task.logissue type=warning]Unable to merge main-vs-deps into the source branch. This could mean that main-vs-deps doesn't exist or could indicate a network issue." + exit 0 } \ No newline at end of file diff --git a/src/Analyzers/CSharp/Analyzers/MisplacedUsingDirectives/MisplacedUsingDirectivesDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/MisplacedUsingDirectives/MisplacedUsingDirectivesDiagnosticAnalyzer.cs index 95def5d42e20f..6c3993d33454c 100644 --- a/src/Analyzers/CSharp/Analyzers/MisplacedUsingDirectives/MisplacedUsingDirectivesDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/MisplacedUsingDirectives/MisplacedUsingDirectivesDiagnosticAnalyzer.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; diff --git a/src/Analyzers/CSharp/Analyzers/UseExpressionBody/Helpers/UseExpressionBodyForAccessorsHelper.cs b/src/Analyzers/CSharp/Analyzers/UseExpressionBody/Helpers/UseExpressionBodyForAccessorsHelper.cs index d44b9ec0414ea..a059441051ba5 100644 --- a/src/Analyzers/CSharp/Analyzers/UseExpressionBody/Helpers/UseExpressionBodyForAccessorsHelper.cs +++ b/src/Analyzers/CSharp/Analyzers/UseExpressionBody/Helpers/UseExpressionBodyForAccessorsHelper.cs @@ -20,7 +20,7 @@ private UseExpressionBodyForAccessorsHelper() new LocalizableResourceString(nameof(CSharpAnalyzersResources.Use_expression_body_for_accessors), CSharpAnalyzersResources.ResourceManager, typeof(CSharpAnalyzersResources)), new LocalizableResourceString(nameof(CSharpAnalyzersResources.Use_block_body_for_accessors), CSharpAnalyzersResources.ResourceManager, typeof(CSharpAnalyzersResources)), CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, - ImmutableArray.Create(SyntaxKind.GetAccessorDeclaration, SyntaxKind.SetAccessorDeclaration, SyntaxKind.InitAccessorDeclaration)) + ImmutableArray.Create(SyntaxKind.GetAccessorDeclaration, SyntaxKind.SetAccessorDeclaration, SyntaxKind.InitAccessorDeclaration, SyntaxKind.AddAccessorDeclaration, SyntaxKind.RemoveAccessorDeclaration)) { } diff --git a/src/Analyzers/CSharp/Analyzers/UseIsNullCheck/CSharpUseNullCheckOverTypeCheckDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseIsNullCheck/CSharpUseNullCheckOverTypeCheckDiagnosticAnalyzer.cs index 22b05951d2320..5ebc11a04aa7d 100644 --- a/src/Analyzers/CSharp/Analyzers/UseIsNullCheck/CSharpUseNullCheckOverTypeCheckDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UseIsNullCheck/CSharpUseNullCheckOverTypeCheckDiagnosticAnalyzer.cs @@ -32,10 +32,12 @@ protected override void InitializeWorker(AnalysisContext context) { context.RegisterCompilationStartAction(context => { - if (context.Compilation.LanguageVersion() < LanguageVersion.CSharp9) + var compilation = context.Compilation; + if (compilation.LanguageVersion() < LanguageVersion.CSharp9) return; - context.RegisterOperationAction(c => AnalyzeIsTypeOperation(c), OperationKind.IsType); + var expressionType = compilation.ExpressionOfTType(); + context.RegisterOperationAction(c => AnalyzeIsTypeOperation(c, expressionType), OperationKind.IsType); context.RegisterOperationAction(c => AnalyzeNegatedPatternOperation(c), OperationKind.NegatedPattern); }); } @@ -80,15 +82,19 @@ private void AnalyzeNegatedPatternOperation(OperationAnalysisContext context) } } - private void AnalyzeIsTypeOperation(OperationAnalysisContext context) + private void AnalyzeIsTypeOperation(OperationAnalysisContext context, INamedTypeSymbol? expressionType) { - if (!ShouldAnalyze(context, out var severity) || - context.Operation.Syntax is not BinaryExpressionSyntax) - { + var operation = context.Operation; + var syntax = operation.Syntax; + + if (!ShouldAnalyze(context, out var severity) || syntax is not BinaryExpressionSyntax) return; - } - var isTypeOperation = (IIsTypeOperation)context.Operation; + if (CSharpSemanticFacts.Instance.IsInExpressionTree(operation.SemanticModel, syntax, expressionType, context.CancellationToken)) + return; + + var isTypeOperation = (IIsTypeOperation)operation; + // Matches 'x is MyType' // isTypeOperation.TypeOperand is 'MyType' // isTypeOperation.ValueOperand.Type is the type of 'x'. @@ -99,7 +105,7 @@ private void AnalyzeIsTypeOperation(OperationAnalysisContext context) { context.ReportDiagnostic( DiagnosticHelper.Create( - Descriptor, context.Operation.Syntax.GetLocation(), severity, additionalLocations: null, properties: null)); + Descriptor, syntax.GetLocation(), severity, additionalLocations: null, properties: null)); } } } diff --git a/src/Analyzers/CSharp/Analyzers/UseParameterNullChecking/CSharpUseParameterNullCheckingDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/UseParameterNullChecking/CSharpUseParameterNullCheckingDiagnosticAnalyzer.cs index e28d2fdab642a..e6402204cebb3 100644 --- a/src/Analyzers/CSharp/Analyzers/UseParameterNullChecking/CSharpUseParameterNullCheckingDiagnosticAnalyzer.cs +++ b/src/Analyzers/CSharp/Analyzers/UseParameterNullChecking/CSharpUseParameterNullCheckingDiagnosticAnalyzer.cs @@ -154,6 +154,22 @@ private void AnalyzeSyntax( additionalLocations: new[] { parameterSyntax.GetLocation() }, properties: null)); } + else + { + var descendants = statement.DescendantNodesAndSelf(descendIntoChildren: static c => c is StatementSyntax); + foreach (var descendant in descendants) + { + // Mostly, we are fine with simplifying null checks in a way that + // causes us to *throw a different exception than before* for some inputs. + // However, we don't want to change semantics such that we + // *throw an exception instead of returning* or vice-versa. + // Therefore we ignore any null checks which are syntactically preceded by conditional or unconditional returns. + if (descendant is ReturnStatementSyntax) + { + return; + } + } + } } return; @@ -186,10 +202,7 @@ bool ParameterCanUseNullChecking([NotNullWhen(true)] IParameterSymbol? parameter ExpressionSyntax left, right; switch (ifStatement) { - case { Condition: BinaryExpressionSyntax { OperatorToken.RawKind: (int)SyntaxKind.EqualsEqualsToken } binary } - // Only suggest the fix on built-in `==` operators where we know we won't change behavior - when semanticModel.GetSymbolInfo(binary).Symbol is IMethodSymbol { MethodKind: MethodKind.BuiltinOperator }: - + case { Condition: BinaryExpressionSyntax { OperatorToken.RawKind: (int)SyntaxKind.EqualsEqualsToken } binary }: left = binary.Left; right = binary.Right; break; @@ -229,7 +242,9 @@ when semanticModel.GetSymbolInfo(binary).Symbol is IMethodSymbol { MethodKind: M return null; } - return (parameterInBinary, ifStatement.GetLocation()); + // The if statement could be associated with an arbitrarily complex else clause. We only want to highlight the "if" part which is removed by the fix. + var location = Location.Create(ifStatement.SyntaxTree, Text.TextSpan.FromBounds(ifStatement.SpanStart, ifStatement.Statement.Span.End)); + return (parameterInBinary, location); // this.field = param ?? throw new ArgumentNullException(nameof(param)); case ExpressionStatementSyntax diff --git a/src/Analyzers/CSharp/CodeFixes/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProvider.cs index a557daa6bb1e6..443f23137674d 100644 --- a/src/Analyzers/CSharp/CodeFixes/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProvider.cs @@ -10,7 +10,7 @@ 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.CodeStyle; diff --git a/src/Analyzers/CSharp/CodeFixes/UseParameterNullChecking/CSharpUseParameterNullCheckingCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/UseParameterNullChecking/CSharpUseParameterNullCheckingCodeFixProvider.cs index 6da8f754e67b9..3b3badcacc4e8 100644 --- a/src/Analyzers/CSharp/CodeFixes/UseParameterNullChecking/CSharpUseParameterNullCheckingCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/UseParameterNullChecking/CSharpUseParameterNullCheckingCodeFixProvider.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Immutable; using System.Composition; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; @@ -56,10 +57,17 @@ protected override Task FixAllAsync( switch (node) { case ExpressionSyntax { Parent: BinaryExpressionSyntax(SyntaxKind.CoalesceExpression) nullCoalescing }: - // this.item = item ?? throw new ArgumentNullException(nameof(item)); var parameterReferenceSyntax = nullCoalescing.Left; editor.ReplaceNode(nullCoalescing, parameterReferenceSyntax.WithAppendedTrailingTrivia(SyntaxFactory.ElasticMarker)); break; + case IfStatementSyntax { Else.Statement: BlockSyntax { Statements: var statementsWithinElse } } ifStatementWithElseBlock: + var parent = (BlockSyntax)ifStatementWithElseBlock.GetRequiredParent(); + var newStatements = parent.Statements.ReplaceRange(ifStatementWithElseBlock, statementsWithinElse.Select(s => s.WithPrependedLeadingTrivia(SyntaxFactory.ElasticMarker))); + editor.ReplaceNode(parent, parent.WithStatements(newStatements)); + break; + case IfStatementSyntax { Else.Statement: StatementSyntax statementWithinElse }: + editor.ReplaceNode(node, statementWithinElse.WithPrependedLeadingTrivia(SyntaxFactory.ElasticMarker)); + break; case IfStatementSyntax: case ExpressionStatementSyntax { Expression: AssignmentExpressionSyntax { Right: BinaryExpressionSyntax(SyntaxKind.CoalesceExpression) } }: editor.RemoveNode(node); diff --git a/src/Analyzers/CSharp/Tests/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProviderTests.cs b/src/Analyzers/CSharp/Tests/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProviderTests.cs index e26c013a693f4..40487c1c27621 100644 --- a/src/Analyzers/CSharp/Tests/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProviderTests.cs +++ b/src/Analyzers/CSharp/Tests/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProviderTests.cs @@ -3,7 +3,7 @@ // 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.CodeFixes; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp; diff --git a/src/Analyzers/CSharp/Tests/PopulateSwitch/PopulateSwitchExpressionTests.cs b/src/Analyzers/CSharp/Tests/PopulateSwitch/PopulateSwitchExpressionTests.cs index 43c60417ab48b..feac80d1e73e5 100644 --- a/src/Analyzers/CSharp/Tests/PopulateSwitch/PopulateSwitchExpressionTests.cs +++ b/src/Analyzers/CSharp/Tests/PopulateSwitch/PopulateSwitchExpressionTests.cs @@ -1261,5 +1261,111 @@ public enum E " ); } + + [Fact, WorkItem(58468, "https://github.com/dotnet/roslyn/issues/58468")] + public async Task NotOnOrPatternWhichAlwaysSucceeds1() + { + await TestMissingInRegularAndScriptAsync( +@" +enum Greeting +{ + Hello, + Goodbye +}; + +class C +{ + void M() + { + Greeting greeting = Greeting.Hello; + string message = greeting [||]switch + { + Greeting.Hello => ""Hey!"", + Greeting.Goodbye or _ => ""Not sure what to say 🤔"" + }; + } +} +"); + } + + [Fact, WorkItem(58468, "https://github.com/dotnet/roslyn/issues/58468")] + public async Task NotOnOrPatternWhichAlwaysSucceeds2() + { + await TestMissingInRegularAndScriptAsync( +@" +enum Greeting +{ + Hello, + Goodbye +}; + +class C +{ + void M() + { + Greeting greeting = Greeting.Hello; + string message = greeting [||]switch + { + Greeting.Hello => ""Hey!"", + _ or Greeting.Goodbye => ""Not sure what to say 🤔"" + }; + } +} +"); + } + + [Fact, WorkItem(58468, "https://github.com/dotnet/roslyn/issues/58468")] + public async Task NotOnOrPatternWhichAlwaysSucceeds3() + { + await TestMissingInRegularAndScriptAsync( +@" +enum Greeting +{ + Hello, + Goodbye +}; + +class C +{ + void M() + { + Greeting greeting = Greeting.Hello; + string message = greeting [||]switch + { + Greeting.Hello => ""Hey!"", + Greeting.Goodbye => ""Bye!"", + _ and var v => ""Not sure what to say 🤔"" + }; + } +} +"); + } + + [Fact, WorkItem(58468, "https://github.com/dotnet/roslyn/issues/58468")] + public async Task NotOnOrPatternWhichAlwaysSucceeds4() + { + await TestMissingInRegularAndScriptAsync( +@" +enum Greeting +{ + Hello, + Goodbye +}; + +class C +{ + void M() + { + Greeting greeting = Greeting.Hello; + string message = greeting [||]switch + { + Greeting.Hello => ""Hey!"", + Greeting.Goodbye => ""Bye!"", + var x and var y => ""Not sure what to say 🤔"" + }; + } +} +"); + } } } diff --git a/src/Analyzers/CSharp/Tests/UseExpressionBody/UseExpressionBodyForAccessorsAnalyzerTests.cs b/src/Analyzers/CSharp/Tests/UseExpressionBody/UseExpressionBodyForAccessorsAnalyzerTests.cs index b567c8841a246..ffc0cf388cfe5 100644 --- a/src/Analyzers/CSharp/Tests/UseExpressionBody/UseExpressionBodyForAccessorsAnalyzerTests.cs +++ b/src/Analyzers/CSharp/Tests/UseExpressionBody/UseExpressionBodyForAccessorsAnalyzerTests.cs @@ -337,6 +337,43 @@ int Goo await TestWithUseExpressionBody(code, fixedCode); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + [WorkItem(59255, "https://github.com/dotnet/roslyn/issues/59255")] + public async Task TestUseExpressionBody5() + { + var code = @" +using System; + +class C +{ + event EventHandler Goo + { + {|IDE0027:add + { + throw new NotImplementedException(); + }|} + + {|IDE0027:remove + { + throw new NotImplementedException(); + }|} + } +}"; + var fixedCode = @" +using System; + +class C +{ + event EventHandler Goo + { + add => throw new NotImplementedException(); + + remove => throw new NotImplementedException(); + } +}"; + await TestWithUseExpressionBody(code, fixedCode); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestUseBlockBody1() { @@ -508,6 +545,42 @@ C this[int index] }.RunAsync(); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + [WorkItem(59255, "https://github.com/dotnet/roslyn/issues/59255")] + public async Task TestUseBlockBody6() + { + var code = @" +using System; + +class C +{ + event EventHandler Goo + { + {|IDE0027:add => throw new NotImplementedException();|} + {|IDE0027:remove => throw new NotImplementedException();|} + } + }"; + var fixedCode = @" +using System; + +class C +{ + event EventHandler Goo + { + add + { + throw new NotImplementedException(); + } + + remove + { + throw new NotImplementedException(); + } + } +}"; + await TestWithUseBlockBodyIncludingPropertiesAndIndexers(code, fixedCode); + } + [WorkItem(20350, "https://github.com/dotnet/roslyn/issues/20350")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestAccessorListFormatting() diff --git a/src/Analyzers/CSharp/Tests/UseIsNullCheck/UseNullCheckOverTypeCheckDiagnosticAnalyzerTests.cs b/src/Analyzers/CSharp/Tests/UseIsNullCheck/UseNullCheckOverTypeCheckDiagnosticAnalyzerTests.cs index 4f6ead28d789f..8bb6898ab764c 100644 --- a/src/Analyzers/CSharp/Tests/UseIsNullCheck/UseNullCheckOverTypeCheckDiagnosticAnalyzerTests.cs +++ b/src/Analyzers/CSharp/Tests/UseIsNullCheck/UseNullCheckOverTypeCheckDiagnosticAnalyzerTests.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.CSharp.UseIsNullCheck; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UseIsNullCheck @@ -202,5 +203,27 @@ public bool M(string value) "; await VerifyCSharp9Async(source, fixedSource); } + + [Fact, WorkItem(58377, "https://github.com/dotnet/roslyn/issues/58377")] + public async Task TestNotInExpressionTree() + { + var source = @" +using System; +using System.Linq.Expressions; + +class SomeClass +{ + void M() + { + Bar(s => s is object ? 0 : 1); + } + + private void Bar(Expression> p) + { + } +} +"; + await VerifyCSharp9Async(source, source); + } } } diff --git a/src/Analyzers/CSharp/Tests/UseParameterNullChecking/UseParameterNullCheckingTests.cs b/src/Analyzers/CSharp/Tests/UseParameterNullChecking/UseParameterNullCheckingTests.cs index 2b8b1aab81723..114b1a7e80ba9 100644 --- a/src/Analyzers/CSharp/Tests/UseParameterNullChecking/UseParameterNullCheckingTests.cs +++ b/src/Analyzers/CSharp/Tests/UseParameterNullChecking/UseParameterNullCheckingTests.cs @@ -3,16 +3,12 @@ // See the LICENSE file in the project root for more information. using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; using Microsoft.CodeAnalysis.CSharp.UseParameterNullChecking; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; -using Xunit.Abstractions; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UseParameterNullChecking { @@ -52,6 +48,36 @@ void M(string s!!) }.RunAsync(); } + [Fact] + [Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestNullableParameterType() + { + await new VerifyCS.Test() + { + TestCode = @"#nullable enable +using System; + +class C +{ + void M(string? s) + { + [|if (s is null) + throw new ArgumentNullException(nameof(s));|] + } +}", + FixedCode = @"#nullable enable +using System; + +class C +{ + void M(string? s!!) + { + } +}", + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + [Theory] [Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] [InlineData("==")] @@ -615,9 +641,9 @@ public async Task TestOutParameter() class C { - public C(out string s) + public {|CS0177:C|}(out string s) { - if (s is null) + if ({|CS0269:s|} is null) throw new ArgumentNullException(nameof(s)); } }"; @@ -625,7 +651,6 @@ public C(out string s) { TestCode = testCode, FixedCode = testCode, - CompilerDiagnostics = Testing.CompilerDiagnostics.None, LanguageVersion = LanguageVersionExtensions.CSharpNext }.RunAsync(); } @@ -1230,6 +1255,57 @@ class C }.RunAsync(); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestDiscard1() + { + await new VerifyCS.Test() + { + TestCode = @"using System; + +class C +{ + Action lambda = _ => + { + [|if (_ is null) + throw new ArgumentNullException(nameof(_));|] + }; +} +", + FixedCode = @"using System; + +class C +{ + Action lambda = _!! => + { + }; +} +", + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestDiscard2() + { + var testCode = @" +using System; + +class C +{ + Action lambda = (_, _) => + { + if ({|CS0103:_|} is null) + throw new ArgumentNullException(nameof({|CS0103:_|})); + }; +}"; + await new VerifyCS.Test() + { + TestCode = testCode, + FixedCode = testCode, + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] public async Task TestAnonymousMethod() { @@ -1318,21 +1394,292 @@ void local() } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] - public async Task TestNotWithUserDefinedOperator() + public async Task TestNotAfterReturn1() { var testCode = @"using System; class C { - public static bool operator ==(C c1, C c2) => true; - public static bool operator !=(C c1, C c2) => false; - static void M(C c) { + return; if (c == null) throw new ArgumentNullException(nameof(c)); } -} -"; +}"; + await new VerifyCS.Test() + { + TestCode = testCode, + FixedCode = testCode, + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestNotAfterReturn2() + { + var testCode = @"using System; +class C +{ + static void M(C c, bool b) + { + if (b) + return; + + if (c == null) + throw new ArgumentNullException(nameof(c)); + } +}"; + await new VerifyCS.Test() + { + TestCode = testCode, + FixedCode = testCode, + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestNotAfterReturn3() + { + var testCode = @"using System; +class C +{ + static void M(C c, bool b) + { + if (b) + { + return; + } + + if (c == null) + throw new ArgumentNullException(nameof(c)); + } +}"; + await new VerifyCS.Test() + { + TestCode = testCode, + FixedCode = testCode, + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestNotAfterReturn4() + { + var testCode = @"using System; +class C +{ + static int M(C c, bool b) + { + if (b) + { + return 0; + } + + if (c == null) + throw new ArgumentNullException(nameof(c)); + + return 0; + } +}"; + await new VerifyCS.Test() + { + TestCode = testCode, + FixedCode = testCode, + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestBeforeReturn1() + { + await new VerifyCS.Test() + { + TestCode = @"using System; +class C +{ + static int M(C c) + { + [|if (c == null) + throw new ArgumentNullException(nameof(c));|] + + return 0; + } +}", + FixedCode = @"using System; +class C +{ + static int M(C c!!) + { + return 0; + } +}", + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestBeforeReturn2() + { + await new VerifyCS.Test() + { + TestCode = @"using System; +class C +{ + static void M(C c, bool b) + { + [|if (c == null) + throw new ArgumentNullException(nameof(c));|] + + if (b) + return; + } +}", + FixedCode = @"using System; +class C +{ + static void M(C c!!, bool b) + { + if (b) + return; + } +}", + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestAfterThrow1() + { + await new VerifyCS.Test() + { + TestCode = @"using System; +class C +{ + static void M(C c) + { + throw new ArgumentOutOfRangeException(); + + [|if (c == null) + throw new ArgumentNullException(nameof(c));|] + } +}", + FixedCode = @"using System; +class C +{ + static void M(C c!!) + { + throw new ArgumentOutOfRangeException(); + } +}", + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestAfterThrow2() + { + await new VerifyCS.Test() + { + TestCode = @"using System; +class C +{ + static void M(int i, C c) + { + if (i < 0) + throw new ArgumentOutOfRangeException(); + + [|if (c == null) + throw new ArgumentNullException(nameof(c));|] + } +}", + FixedCode = @"using System; +class C +{ + static void M(int i, C c!!) + { + if (i < 0) + throw new ArgumentOutOfRangeException(); + } +}", + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestExtensionMethod() + { + await new VerifyCS.Test() + { + TestCode = @"using System; +interface I { } +static class C +{ + static void M(this I i) + { + [|if (i == null) + throw new ArgumentNullException(nameof(i));|] + } +}", + FixedCode = @"using System; +interface I { } +static class C +{ + static void M(this I i!!) + { + } +}", + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestNullCheckInBaseClause() + { + // Applying code fix introduces CS8602: Dereference of a possibly null reference. + // In this case, the user needs to change '?.' to '.' in the base clause. + await new VerifyCS.Test() + { + TestCode = @"#nullable enable +using System; + +class Base { public Base(string? x) { } } +class C : Base +{ + public C(string x) : base(x?.ToString()) + { + [|if (x == null) { throw new ArgumentNullException(); }|] + x.ToString(); + } +}", + FixedCode = @"#nullable enable +using System; + +class Base { public Base(string? x) { } } +class C : Base +{ + public C(string x!!) : base(x?.ToString()) + { + {|CS8602:x|}.ToString(); + } +}", + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestLabeledNullCheck() + { + // A label syntactically contains the following statement + // and we don't offer the fix on nested statements within the body. + var testCode = @"using System; +public class C +{ + public void M(string s) + { + label1: + if (s == null) throw new ArgumentNullException(); + } +}"; await new VerifyCS.Test() { TestCode = testCode, @@ -1341,6 +1688,287 @@ static void M(C c) }.RunAsync(); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestReturnBackwardsBranchToNullCheck() + { + // In this scenario, applying the fix makes us throw instead of returning. + // However, we think it's esoteric enough that we don't need to address it. + await new VerifyCS.Test() + { + TestCode = @"using System; +public class C +{ + public void M(string s, int i = 0) + { + goto label2; + + label1: + ; + [|if (s == null) throw new ArgumentNullException();|] + return; + + label2: + if (i < 0) return; + goto label1; + } +}", + FixedCode = @"using System; +public class C +{ + public void M(string s!!, int i = 0) + { + goto label2; + + label1: + ; + return; + + label2: + if (i < 0) return; + goto label1; + } +}", + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestNullCheckWithElse1() + { + await new VerifyCS.Test() + { + TestCode = @"using System; +public class C +{ + public void M(string s) + { + [|if (s == null) throw new ArgumentNullException();|] + else Console.Write(1); + } +}", + FixedCode = @"using System; +public class C +{ + public void M(string s!!) + { + Console.Write(1); + } +}", + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestNullCheckWithElse2() + { + await new VerifyCS.Test() + { + TestCode = @"using System; +public class C +{ + public void M(string s) + { + [|if (s == null) throw new ArgumentNullException();|] + else if (s.Length == 0) Console.Write(1); + } +}", + FixedCode = @"using System; +public class C +{ + public void M(string s!!) + { + if (s.Length == 0) Console.Write(1); + } +}", + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestNullCheckWithElse3() + { + await new VerifyCS.Test() + { + TestCode = @"using System; +public class C +{ + public void M(string s) + { + Console.Write(0); + [|if (s == null) throw new ArgumentNullException();|] + else + { + Console.Write(1); + Console.Write(2); + } + Console.Write(3); + } +}", + FixedCode = @"using System; +public class C +{ + public void M(string s!!) + { + Console.Write(0); + Console.Write(1); + Console.Write(2); + Console.Write(3); + } +}", + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestNullCheckWithElse4() + { + await new VerifyCS.Test() + { + TestCode = @"using System; +public class C +{ + public void M(string s) + { + [|if (s == null) throw new ArgumentNullException();|] + else if (s.Length == 0) + { + Console.Write(1); + Console.Write(2); + } + } +}", + FixedCode = @"using System; +public class C +{ + public void M(string s!!) + { + if (s.Length == 0) + { + Console.Write(1); + Console.Write(2); + } + } +}", + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestNullCheckWithElse5() + { + await new VerifyCS.Test() + { + TestCode = @"using System; +public class C +{ + public void M(string s1, string s2) + { + [|if (s1 == null) throw new ArgumentNullException();|] + else if (s2 == null) throw new ArgumentNullException(); + } +}", + FixedCode = @"using System; +public class C +{ + public void M(string s1!!, string s2!!) + { + } +}", + LanguageVersion = LanguageVersionExtensions.CSharpNext, + NumberOfIncrementalIterations = 2, + NumberOfFixAllIterations = 2 + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestNullCheckWithElse6() + { + await new VerifyCS.Test() + { + TestCode = @"using System; +public class C +{ + public void M(string s1) + { + [|if (s1 == null) throw new ArgumentNullException();|] + else /* comment1 */ s1.ToString() /* comment2 */; // comment3 + } +}", + FixedCode = @"using System; +public class C +{ + public void M(string s1!!) + { + s1.ToString() /* comment2 */; // comment3 + } +}", + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestNullCheckWithElse7() + { + await new VerifyCS.Test() + { + TestCode = @"using System; +public class C +{ + public void M(string s1) + { + [|if (s1 == null) throw new ArgumentNullException();|] + else + { + /* comment1 */ s1.ToString() /* comment2 */; // comment3 + } + } +}", + FixedCode = @"using System; +public class C +{ + public void M(string s1!!) + { + /* comment1 */ + s1.ToString() /* comment2 */; // comment3 + } +}", + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestWithUserDefinedOperator() + { + await new VerifyCS.Test() + { + TestCode = @"using System; +class C +{ + public static bool operator ==(C c1, C c2) => true; + public static bool operator !=(C c1, C c2) => false; + + static void M(C c) + { + [|if (c == null) + throw new ArgumentNullException(nameof(c));|] + } +} +", + FixedCode = @"using System; +class C +{ + public static bool operator ==(C c1, C c2) => true; + public static bool operator !=(C c1, C c2) => false; + + static void M(C c!!) + { + } +} +", + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] public async Task TestWithUnusedUserDefinedOperator() { @@ -1552,6 +2180,33 @@ static unsafe void M(delegate* ptr!!) }.RunAsync(); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestNullableValueType() + { + await new VerifyCS.Test() + { + TestCode = @"using System; +class C +{ + static void M(int? value) + { + [|if (value == null) + throw new ArgumentNullException(nameof(value));|] + } +} +", + FixedCode = @"using System; +class C +{ + static void M(int? value!!) + { + } +} +", + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] public async Task TestPartialMethod() { diff --git a/src/Analyzers/Core/Analyzers/EnforceOnBuildValues.cs b/src/Analyzers/Core/Analyzers/EnforceOnBuildValues.cs index bf6a967e39024..64b23fe592138 100644 --- a/src/Analyzers/Core/Analyzers/EnforceOnBuildValues.cs +++ b/src/Analyzers/Core/Analyzers/EnforceOnBuildValues.cs @@ -96,13 +96,15 @@ internal static class EnforceOnBuildValues public const EnforceOnBuild PopulateSwitchExpression = /*IDE0072*/ EnforceOnBuild.WhenExplicitlyEnabled; public const EnforceOnBuild SimplifyLinqExpression = /*IDE0120*/ EnforceOnBuild.WhenExplicitlyEnabled; public const EnforceOnBuild UseNullCheckOverTypeCheck = /*IDE0150*/ EnforceOnBuild.WhenExplicitlyEnabled; - public const EnforceOnBuild Regex = /*RE0001*/ EnforceOnBuild.WhenExplicitlyEnabled; public const EnforceOnBuild MultipleBlankLines = /*IDE2000*/ EnforceOnBuild.WhenExplicitlyEnabled; public const EnforceOnBuild EmbeddedStatementPlacement = /*IDE2001*/ EnforceOnBuild.WhenExplicitlyEnabled; public const EnforceOnBuild ConsecutiveBracePlacement = /*IDE2002*/ EnforceOnBuild.WhenExplicitlyEnabled; public const EnforceOnBuild ConsecutiveStatementPlacement = /*IDE2003*/ EnforceOnBuild.WhenExplicitlyEnabled; public const EnforceOnBuild ConstructorInitializerPlacement = /*IDE2004*/ EnforceOnBuild.WhenExplicitlyEnabled; + public const EnforceOnBuild Regex = /*RE0001*/ EnforceOnBuild.WhenExplicitlyEnabled; + public const EnforceOnBuild Json = /*JSON001*/ EnforceOnBuild.WhenExplicitlyEnabled; + /* EnforceOnBuild.Never */ // TODO: Allow enforcing simplify names and related diagnostics on build once we validate their performance charactericstics. public const EnforceOnBuild SimplifyNames = /*IDE0001*/ EnforceOnBuild.Never; @@ -113,5 +115,8 @@ internal static class EnforceOnBuildValues public const EnforceOnBuild ConvertAnonymousTypeToTuple = /*IDE0050*/ EnforceOnBuild.Never; public const EnforceOnBuild RemoveUnreachableCode = /*IDE0035*/ EnforceOnBuild.Never; // Non-configurable fading diagnostic corresponding to CS0162. public const EnforceOnBuild RemoveUnnecessarySuppression = /*IDE0079*/ EnforceOnBuild.Never; // IDE-only analyzer. + + // Pure IDE feature for lighting up editor features. Do not enforce on build. + public const EnforceOnBuild DetectProbableJsonStrings = /*JSON002*/ EnforceOnBuild.Never; } } diff --git a/src/Analyzers/Core/Analyzers/Helpers/DiagnosticHelper.cs b/src/Analyzers/Core/Analyzers/Helpers/DiagnosticHelper.cs index b53dcd6787287..36d5d9a48fb88 100644 --- a/src/Analyzers/Core/Analyzers/Helpers/DiagnosticHelper.cs +++ b/src/Analyzers/Core/Analyzers/Helpers/DiagnosticHelper.cs @@ -257,12 +257,13 @@ public static Diagnostic CreateWithMessage( public static string? GetHelpLinkForDiagnosticId(string id) { + // TODO: Add documentation for Regex and Json analyzer + // Tracked with https://github.com/dotnet/roslyn/issues/48530 if (id == "RE0001") - { - // TODO: Add documentation for Regex analyzer - // Tracked with https://github.com/dotnet/roslyn/issues/48530 return null; - } + + if (id.StartsWith("JSON", StringComparison.Ordinal)) + return null; Debug.Assert(id.StartsWith("IDE", StringComparison.Ordinal)); return $"https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/{id.ToLowerInvariant()}"; diff --git a/src/Analyzers/Core/Analyzers/PopulateSwitch/PopulateSwitchExpressionHelpers.cs b/src/Analyzers/Core/Analyzers/PopulateSwitch/PopulateSwitchExpressionHelpers.cs index 814aaa764a0b4..99fd13237f5bd 100644 --- a/src/Analyzers/Core/Analyzers/PopulateSwitch/PopulateSwitchExpressionHelpers.cs +++ b/src/Analyzers/Core/Analyzers/PopulateSwitch/PopulateSwitchExpressionHelpers.cs @@ -70,17 +70,27 @@ private static void RemoveIfConstantPatternHasValue(IOperation operation, Dictio } public static bool HasDefaultCase(ISwitchExpressionOperation operation) - => operation.Arms.Any(a => IsDefault(a)); + => operation.Arms.Any(IsDefault); public static bool IsDefault(ISwitchExpressionArmOperation arm) - { - if (arm.Pattern.Kind == OperationKind.DiscardPattern) - return true; - - if (arm.Pattern is IDeclarationPatternOperation declarationPattern) - return declarationPattern.MatchesNull; + => IsDefault(arm.Pattern); - return false; - } + private static bool IsDefault(IPatternOperation pattern) + => pattern switch + { + // _ => ... + IDiscardPatternOperation => true, + // var v => ... + IDeclarationPatternOperation declarationPattern => declarationPattern.MatchesNull, + IBinaryPatternOperation binaryPattern => binaryPattern.OperatorKind switch + { + // x or _ => ... + BinaryOperatorKind.Or => IsDefault(binaryPattern.LeftPattern) || IsDefault(binaryPattern.RightPattern), + // _ and var x => ... + BinaryOperatorKind.And => IsDefault(binaryPattern.LeftPattern) && IsDefault(binaryPattern.RightPattern), + _ => false, + }, + _ => false + }; } } diff --git a/src/Analyzers/Core/CodeFixes/PredefinedCodeFixProviderNames.cs b/src/Analyzers/Core/CodeFixes/PredefinedCodeFixProviderNames.cs index 94eec78057a11..2d34aede04ddb 100644 --- a/src/Analyzers/Core/CodeFixes/PredefinedCodeFixProviderNames.cs +++ b/src/Analyzers/Core/CodeFixes/PredefinedCodeFixProviderNames.cs @@ -62,6 +62,7 @@ internal static class PredefinedCodeFixProviderNames public const string ImplementInterface = nameof(ImplementInterface); public const string InlineDeclaration = nameof(InlineDeclaration); public const string InvokeDelegateWithConditionalAccess = nameof(InvokeDelegateWithConditionalAccess); + public const string JsonDetection = nameof(JsonDetection); public const string MakeFieldReadonly = nameof(MakeFieldReadonly); public const string MakeLocalFunctionStatic = nameof(MakeLocalFunctionStatic); public const string MakeMemberStatic = nameof(MakeMemberStatic); diff --git a/src/Analyzers/Core/CodeFixes/RemoveUnusedParametersAndValues/AbstractRemoveUnusedValuesCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/RemoveUnusedParametersAndValues/AbstractRemoveUnusedValuesCodeFixProvider.cs index ca46244be1c03..8163e6013baac 100644 --- a/src/Analyzers/Core/CodeFixes/RemoveUnusedParametersAndValues/AbstractRemoveUnusedValuesCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/RemoveUnusedParametersAndValues/AbstractRemoveUnusedValuesCodeFixProvider.cs @@ -274,7 +274,7 @@ protected sealed override async Task FixAllAsync(Document document, ImmutableArr { #if CODE_STYLE var provider = GetSyntaxFormattingService(); - var options = SyntaxFormattingOptions.Create(document.Project.AnalyzerOptions.GetAnalyzerOptionSet(editor.OriginalRoot.SyntaxTree, cancellationToken)); + var options = provider.GetFormattingOptions(document.Project.AnalyzerOptions.GetAnalyzerOptionSet(editor.OriginalRoot.SyntaxTree, cancellationToken)); #else var provider = document.Project.Solution.Workspace.Services; var options = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); diff --git a/src/Analyzers/Core/CodeFixes/UseConditionalExpression/AbstractUseConditionalExpressionCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/UseConditionalExpression/AbstractUseConditionalExpressionCodeFixProvider.cs index 41a90a1ceb2a6..30018fd0c3f3d 100644 --- a/src/Analyzers/Core/CodeFixes/UseConditionalExpression/AbstractUseConditionalExpressionCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/UseConditionalExpression/AbstractUseConditionalExpressionCodeFixProvider.cs @@ -78,7 +78,7 @@ await FixOneAsync( #if CODE_STYLE var provider = GetSyntaxFormattingService(); - var options = SyntaxFormattingOptions.Create(document.Project.AnalyzerOptions.GetAnalyzerOptionSet(root.SyntaxTree, cancellationToken)); + var options = provider.GetFormattingOptions(document.Project.AnalyzerOptions.GetAnalyzerOptionSet(root.SyntaxTree, cancellationToken)); #else var provider = document.Project.Solution.Workspace.Services; var options = await SyntaxFormattingOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); diff --git a/src/CodeStyle/CSharp/Tests/FormattingAnalyzerTests.cs b/src/CodeStyle/CSharp/Tests/FormattingAnalyzerTests.cs index d078794b7f5e8..ba4e9f8f1d13a 100644 --- a/src/CodeStyle/CSharp/Tests/FormattingAnalyzerTests.cs +++ b/src/CodeStyle/CSharp/Tests/FormattingAnalyzerTests.cs @@ -7,14 +7,16 @@ using System.IO; using System.Text; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp.Shared.Extensions; using Microsoft.CodeAnalysis.CSharp.Testing; +using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Testing.Verifiers; using Microsoft.CodeAnalysis.Text; using Xunit; namespace Microsoft.CodeAnalysis.CodeStyle { - using Verify = CSharpCodeFixVerifier; + using Verify = CSharpCodeFixVerifier; public class FormattingAnalyzerTests { @@ -33,6 +35,25 @@ void MyMethod() await Verify.VerifyAnalyzerAsync(testCode); } + [Fact] + public async Task TestParamNullChecking() + { + var testCode = @" +class MyClass +{ + void MyMethod(string s!!) + { + } +} +"; + await new Verify.Test + { + TestCode = testCode, + FixedCode = testCode, + LanguageVersion = LanguageVersionExtensions.CSharpNext + }.RunAsync(); + } + [Fact] public async Task TestNeedsIndentation() { diff --git a/src/CodeStyle/Core/Analyzers/AbstractFormattingAnalyzer.cs b/src/CodeStyle/Core/Analyzers/AbstractFormattingAnalyzer.cs index 3b51c026c3ec0..dbeaf6f74148b 100644 --- a/src/CodeStyle/Core/Analyzers/AbstractFormattingAnalyzer.cs +++ b/src/CodeStyle/Core/Analyzers/AbstractFormattingAnalyzer.cs @@ -34,7 +34,7 @@ protected sealed override void InitializeWorker(AnalysisContext context) private void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context) { - var options = SyntaxFormattingOptions.Create(context.Options.AnalyzerConfigOptionsProvider.GetOptions(context.Tree)); + var options = SyntaxFormattingService.GetFormattingOptions(context.Options.AnalyzerConfigOptionsProvider.GetOptions(context.Tree)); FormattingAnalyzerHelper.AnalyzeSyntaxTree(context, SyntaxFormattingService, Descriptor, options); } } diff --git a/src/CodeStyle/Core/CodeFixes/FormattingCodeFixProvider.cs b/src/CodeStyle/Core/CodeFixes/FormattingCodeFixProvider.cs index b2782fc2ace61..e7550a1dde299 100644 --- a/src/CodeStyle/Core/CodeFixes/FormattingCodeFixProvider.cs +++ b/src/CodeStyle/Core/CodeFixes/FormattingCodeFixProvider.cs @@ -47,12 +47,11 @@ private async Task FixOneAsync(CodeFixContext context, Diagnostic diag return context.Document.WithText(await updatedTree.GetTextAsync(cancellationToken).ConfigureAwait(false)); } - private static async Task GetOptionsAsync(Document document, CancellationToken cancellationToken) + private async Task GetOptionsAsync(Document document, CancellationToken cancellationToken) { var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var analyzerConfigOptions = document.Project.AnalyzerOptions.AnalyzerConfigOptionsProvider.GetOptions(tree); - - return SyntaxFormattingOptions.Create(analyzerConfigOptions); + return SyntaxFormattingService.GetFormattingOptions(analyzerConfigOptions); } public sealed override FixAllProvider GetFixAllProvider() diff --git a/src/CodeStyle/Core/CodeFixes/Host/Mef/CodeStyleHostLanguageServices.cs.cs b/src/CodeStyle/Core/CodeFixes/Host/Mef/CodeStyleHostLanguageServices.cs.cs index fc8555e468e05..9c77274388f71 100644 --- a/src/CodeStyle/Core/CodeFixes/Host/Mef/CodeStyleHostLanguageServices.cs.cs +++ b/src/CodeStyle/Core/CodeFixes/Host/Mef/CodeStyleHostLanguageServices.cs.cs @@ -2,16 +2,17 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable disable + using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Composition.Convention; +using System.Composition; using System.Composition.Hosting; using System.Linq; using System.Reflection; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Host { @@ -27,7 +28,7 @@ private MefHostExportProvider(CompositionHost compositionContext) public static MefHostExportProvider Create(string languageName) { var assemblies = CreateAssemblies(languageName); - var compositionConfiguration = new ContainerConfiguration().WithAssemblies(assemblies, CodeStyleAttributedModelProvider.Instance); + var compositionConfiguration = new ContainerConfiguration().WithAssemblies(assemblies); return new MefHostExportProvider(compositionConfiguration.CreateContainer()); } @@ -55,79 +56,16 @@ IEnumerable> IMefHostExportProvider.GetExports() => _compositionContext.GetExports().Select(e => new Lazy(() => e)); IEnumerable> IMefHostExportProvider.GetExports() - => _compositionContext.GetExports>(); - - /// - /// Custom implementation of which excludes MEF parts intended for - /// languages not supported by the code style layer (only C# and Visual Basic are supported here). This is a - /// workaround for the fact that MEF 2 does not silently reject MEF parts with missing required imports, - /// which differs from MEF 1 and VS-MEF which are used elsewhere in the product. - /// - /// - private sealed class CodeStyleAttributedModelProvider : AttributedModelProvider { - public static readonly CodeStyleAttributedModelProvider Instance = new(); - - public override IEnumerable GetCustomAttributes(Type reflectedType, MemberInfo member) - { - _ = reflectedType ?? throw new ArgumentNullException(nameof(reflectedType)); - _ = member ?? throw new ArgumentNullException(nameof(member)); - - if (member is not System.Reflection.TypeInfo && (object)member.DeclaringType != reflectedType) - return Array.Empty(); - - return FilterCustomAttributes(CustomAttributeExtensions.GetCustomAttributes(member, inherit: false)); - } - - public override IEnumerable GetCustomAttributes(Type reflectedType, ParameterInfo parameter) - { - _ = reflectedType ?? throw new ArgumentNullException(nameof(reflectedType)); - _ = parameter ?? throw new ArgumentNullException(nameof(parameter)); - - return FilterCustomAttributes(CustomAttributeExtensions.GetCustomAttributes(parameter, inherit: false)); - } - - private static IEnumerable FilterCustomAttributes(IEnumerable attributes) - { - var inputArray = attributes.AsArray(); - List? outputArray = null; - for (var i = 0; i < inputArray.Length; i++) - { - if (IsExcluded(inputArray[i])) - { - if (outputArray is null) - { - if (i == 0 && inputArray.Length == 1) - { - return Array.Empty(); - } - - outputArray = new List(inputArray.Length - 1); - for (var j = 0; j < i; j++) - { - outputArray.Add(inputArray[i]); - } - } - - // Don't add the current item to the output array - continue; - } - - outputArray?.Add(inputArray[i]); - } - - return outputArray?.ToArray() ?? inputArray; - - static bool IsExcluded(Attribute attribute) - { - // Exclude language service exports that don't apply to C# or Visual Basic - if (attribute is ExportLanguageServiceAttribute { Language: not (LanguageNames.CSharp or LanguageNames.VisualBasic) }) - return true; + var importer = new WithMetadataImporter(); + _compositionContext.SatisfyImports(importer); + return importer.Exports; + } - // Include this attribute - return false; - } - } + private class WithMetadataImporter + { + [ImportMany] + public IEnumerable> Exports { get; set; } } } } diff --git a/src/CodeStyle/Tools/Program.cs b/src/CodeStyle/Tools/Program.cs index d5294a6097187..911aca1be5881 100644 --- a/src/CodeStyle/Tools/Program.cs +++ b/src/CodeStyle/Tools/Program.cs @@ -70,7 +70,7 @@ private static void CreateGlobalConfigFiles(string language, string outputDir, I { CreateGlobalconfig( configDir, - $"AnalysisLevelStyle_{analysisMode}.editorconfig", + $"AnalysisLevelStyle_{analysisMode}.editorconfig".ToLowerInvariant(), (AnalysisMode)analysisMode!, allRulesById); } diff --git a/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj b/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj index 383385729d071..bcc0932af7fa4 100644 --- a/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj +++ b/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj @@ -32,6 +32,7 @@ + diff --git a/src/Compilers/CSharp/CSharpCodeAnalysisRules.ruleset b/src/Compilers/CSharp/CSharpCodeAnalysisRules.ruleset deleted file mode 100644 index dcafed64434b5..0000000000000 --- a/src/Compilers/CSharp/CSharpCodeAnalysisRules.ruleset +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file 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 a11f9e07bb228..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); } 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/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/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..0192afe47b90b 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundSwitchStatement.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundSwitchStatement.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; +using System.Diagnostics; namespace Microsoft.CodeAnalysis.CSharp { @@ -10,5 +11,24 @@ internal partial class BoundSwitchStatement : IBoundSwitchStatement { 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 c4557d6b39a7e..5fd068b866369 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. @@ -6893,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. @@ -6941,4 +6983,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + \ No newline at end of file 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/CSharpSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs index 0b0bf6249fc41..7a4906cddaddc 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) { 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 e3161bc1b2e79..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: diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 450c5f645296b..f891efdf9ae55 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2020,13 +2020,31 @@ internal enum ErrorCode ERR_StructHasInitializersAndNoDeclaredConstructor = 8983, ERR_EncUpdateFailedDelegateTypeChanged = 8984, - ERR_IncorrectNullCheckSyntax = 8990, + ERR_DiscardCannotBeNullChecked = 8990, ERR_MustNullCheckInImplementation = 8991, ERR_NonNullableValueTypeIsNullChecked = 8992, WRN_NullCheckedHasDefaultNull = 8993, 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/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index 73accd97ff336..c3a022ba2bbde 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -243,6 +243,7 @@ internal enum MessageID IDS_ParameterNullChecking = MessageBase + 12815, IDS_FeatureCacheStaticMethodGroupConversion = MessageBase + 12816, + IDS_FeatureRawStringLiterals = MessageBase + 12817, } // Message IDs may refer to strings that need to be localized. @@ -352,6 +353,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) // PREFER reporting diagnostics in binding when diagnostics do not affect the shape of the syntax tree // C# preview features. + case MessageID.IDS_FeatureRawStringLiterals: case MessageID.IDS_FeatureStaticAbstractMembersInInterfaces: // semantic check case MessageID.IDS_FeatureGenericAttributes: // semantic check case MessageID.IDS_FeatureNewLinesInInterpolations: // semantic check 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/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_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_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/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 bfe6488af215c..d0a0ac11e529c 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -10161,8 +10161,13 @@ private bool IsPossibleExpression(bool allowBinaryExpressions, bool allowAssignm case SyntaxKind.OpenParenToken: case SyntaxKind.NumericLiteralToken: case SyntaxKind.StringLiteralToken: - case SyntaxKind.InterpolatedStringStartToken: + case SyntaxKind.SingleLineRawStringLiteralToken: + case SyntaxKind.MultiLineRawStringLiteralToken: case SyntaxKind.InterpolatedStringToken: + case SyntaxKind.InterpolatedStringStartToken: + case SyntaxKind.InterpolatedVerbatimStringStartToken: + case SyntaxKind.InterpolatedSingleLineRawStringStartToken: + case SyntaxKind.InterpolatedMultiLineRawStringStartToken: case SyntaxKind.CharacterLiteralToken: case SyntaxKind.NewKeyword: case SyntaxKind.DelegateKeyword: @@ -10445,8 +10450,13 @@ private bool IsAwaitExpression() case SyntaxKind.TrueKeyword: case SyntaxKind.FalseKeyword: case SyntaxKind.StringLiteralToken: - case SyntaxKind.InterpolatedStringStartToken: + case SyntaxKind.SingleLineRawStringLiteralToken: + case SyntaxKind.MultiLineRawStringLiteralToken: case SyntaxKind.InterpolatedStringToken: + case SyntaxKind.InterpolatedStringStartToken: + case SyntaxKind.InterpolatedVerbatimStringStartToken: + case SyntaxKind.InterpolatedSingleLineRawStringStartToken: + case SyntaxKind.InterpolatedMultiLineRawStringStartToken: case SyntaxKind.NumericLiteralToken: case SyntaxKind.NullKeyword: case SyntaxKind.CharacterLiteralToken: @@ -10880,9 +10890,14 @@ private ExpressionSyntax ParseTermWithoutPostfix(Precedence precedence) case SyntaxKind.NullKeyword: case SyntaxKind.NumericLiteralToken: case SyntaxKind.StringLiteralToken: + case SyntaxKind.SingleLineRawStringLiteralToken: + case SyntaxKind.MultiLineRawStringLiteralToken: case SyntaxKind.CharacterLiteralToken: return _syntaxFactory.LiteralExpression(SyntaxFacts.GetLiteralExpression(tk), this.EatToken()); case SyntaxKind.InterpolatedStringStartToken: + case SyntaxKind.InterpolatedVerbatimStringStartToken: + case SyntaxKind.InterpolatedSingleLineRawStringStartToken: + case SyntaxKind.InterpolatedMultiLineRawStringStartToken: throw new NotImplementedException(); // this should not occur because these tokens are produced and parsed immediately case SyntaxKind.InterpolatedStringToken: return this.ParseInterpolatedStringToken(); 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/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 2f98edd93ba78..d367804586e73 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -1,146 +1,8 @@ -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 -*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? +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.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! @@ -151,9 +13,6 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.DestructorDeclaration(Microso *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.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.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! @@ -162,101 +21,10 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.LocalFunctionStatement(Micros *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.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.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.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.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! -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? +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/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/Source/ParameterHelpers.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs index d473e4053ad4f..910cd4273f970 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs @@ -805,6 +805,10 @@ internal static void ReportParameterNullCheckingErrors(DiagnosticBag diagnostics { diagnostics.Add(useSiteInfo.DiagnosticInfo, location); } + if (parameter.IsDiscard) + { + diagnostics.Add(ErrorCode.ERR_DiscardCannotBeNullChecked, location); + } if (parameter.TypeWithAnnotations.NullableAnnotation.IsAnnotated() || parameter.Type.IsNullableTypeOrTypeParameter()) { 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/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/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 49a4d992f79ae..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) diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs index ecff495816ec2..b6252d4c4d2df 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs @@ -485,8 +485,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 @@ -868,5 +870,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 2b39e146d4f58..0c9328b86bf1c 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/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 3578b08227659..cf8a63c0ca222 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -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 „_“. @@ -597,6 +602,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 +642,6 @@ Argumenty s modifikátorem in se nedají použít v dynamicky volaných výrazech. - - Incorrect parameter null checking syntax. Should be '!!'. - Nesprávná syntaxe kontroly hodnoty null parametru Hodnota by měla být !!. - - 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šší. @@ -782,6 +787,16 @@ 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. + + The #line directive end position must be greater than or equal to the start position Koncová pozice direktivy #line musí být vyšší nebo rovna počáteční pozici. @@ -927,6 +942,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. @@ -1057,6 +1082,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. @@ -1197,6 +1242,11 @@ 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. Položka „struct“ s inicializátory pole musí obsahovat explicitně deklarovaný konstruktor. @@ -1222,6 +1272,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ů. @@ -1277,6 +1342,11 @@ Vzory řezů se nedají používat pro hodnotu typu {0}. + + Unterminated raw string literal. + Unterminated raw string literal. + + A generic task-like return type was expected, but the type '{0}' found in 'AsyncMethodBuilder' attribute was not suitable. It must be an unbound generic type of arity one, and its containing type (if any) must be non-generic. Očekával se obecný návratový typ podobný úloze, ale typ {0} nalezený v atributu AsyncMethodBuilder nebyl vhodný. Musí se jednat o nevázaný obecný typ arity a jeho nadřazený typ (pokud existuje) nesmí být obecný. @@ -1377,6 +1447,11 @@ pozice polí v záznamech + + raw string literals + raw string literals + + record structs struktury záznamů diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 3552cd59655ad..f26a9dabd49f8 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -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 "_". @@ -597,6 +602,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 +642,6 @@ Argumente mit dem Modifizierer "in" können nicht in dynamisch gebundenen Ausdrücken verwendet werden. - - Incorrect parameter null checking syntax. Should be '!!'. - Falsche Syntax für die NULL-Überprüfung des Parameters. Muss „!!“ sein. - - 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. @@ -782,6 +787,16 @@ 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. + + The #line directive end position must be greater than or equal to the start position Die Endposition der #line-Anweisung muss größer oder gleich der Startposition sein @@ -927,6 +942,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. @@ -1057,6 +1082,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. @@ -1197,6 +1242,11 @@ 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. Eine „Struktur“ mit Feldinitialisierern muss einen explizit deklarierten Konstruktor enthalten. @@ -1222,6 +1272,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. @@ -1277,6 +1342,11 @@ Segmentmuster dürfen nicht für einen Wert vom Typ „{0}“ verwendet werden. + + Unterminated raw string literal. + Unterminated raw string literal. + + A generic task-like return type was expected, but the type '{0}' found in 'AsyncMethodBuilder' attribute was not suitable. It must be an unbound generic type of arity one, and its containing type (if any) must be non-generic. Ein generischer aufgabenähnlicher Rückgabetyp wurde erwartet, aber der Typ „{0}“, der im Attribut „AsyncMethodBuilder“ gefunden wurde, war nicht geeignet. Es muss sich um einen ungebundenen generischen Typ von Stelligkeit Eins handelt, und der enthaltende Typ (falls vorhanden) muss nicht generisch sein. @@ -1377,6 +1447,11 @@ Positionsfelder in Datensätzen + + raw string literals + raw string literals + + record structs Datensatzstrukturen diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 0279642185344..bf487453d1132 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -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 '_'. @@ -597,6 +602,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 +642,6 @@ No se pueden usar argumentos con el modificador "in" en expresiones distribuidas dinámicamente. - - Incorrect parameter null checking syntax. Should be '!!'. - Sintaxis de comprobación null de parámetro incorrecto. Debe ser '!!'. - - 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. @@ -782,6 +787,16 @@ 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. + + The #line directive end position must be greater than or equal to the start position La posición final de la directiva #line debe ser mayor o igual que la posición inicial @@ -927,6 +942,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. @@ -1057,6 +1082,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. @@ -1197,6 +1242,11 @@ 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. Un 'struct' con inicializadores de campo debe incluir un constructor declarado explícitamente. @@ -1222,6 +1272,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. @@ -1277,6 +1342,11 @@ No se pueden utilizar patrones de segmento para el valor de tipo "{0}". + + Unterminated raw string literal. + Unterminated raw string literal. + + A generic task-like return type was expected, but the type '{0}' found in 'AsyncMethodBuilder' attribute was not suitable. It must be an unbound generic type of arity one, and its containing type (if any) must be non-generic. Se esperaba un tipo de valor devuelto genérico similar a una tarea, pero el tipo "{0}" encontrado en el atributo "AsyncMethodBuilder" no era adecuado. Debe ser un tipo genérico independiente de aridad uno y su tipo contenedor (si existe) debe ser no genérico. @@ -1377,6 +1447,11 @@ campos posicionales en registros + + raw string literals + raw string literals + + record structs registros diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 4a85719407556..42694a4856397 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -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 '_'. @@ -597,6 +602,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 +642,6 @@ Impossible d'utiliser les arguments avec le modificateur 'in' dans les expressions dispatchées dynamiquement. - - Incorrect parameter null checking syntax. Should be '!!'. - Syntaxe de vérification null du paramètre incorrect. Doit être « !! ». - - 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. @@ -782,6 +787,16 @@ 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. + + The #line directive end position must be greater than or equal to the start position La position finale de la directive #line doit être supérieure ou égale à la position initiale. @@ -927,6 +942,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é. @@ -1057,6 +1082,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'. @@ -1197,6 +1242,11 @@ 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. Un 'struct' avec des initialiseurs de champ doit inclure un constructeur explicitement déclaré. @@ -1222,6 +1272,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. @@ -1277,6 +1342,11 @@ 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. + + A generic task-like return type was expected, but the type '{0}' found in 'AsyncMethodBuilder' attribute was not suitable. It must be an unbound generic type of arity one, and its containing type (if any) must be non-generic. Un type de retour de type tâche générique est attendu, mais le type « {0} » trouvé dans l’attribut ’AsyncMethodBuilder’ n’était pas approprié. Il doit s’agir d’un type générique indépendant d’arité One, et son type conteneur (le cas échéant) doit être non générique. @@ -1377,6 +1447,11 @@ champs positionnels dans les enregistrements + + raw string literals + raw string literals + + record structs structs d’enregistrement diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index a9b269f4d63bf..970507838682e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -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 '_'. @@ -597,6 +602,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 +642,6 @@ Non è possibile usare argomenti con il modificatore 'in' nelle espressioni inviate in modo dinamico. - - Incorrect parameter null checking syntax. Should be '!!'. - Sintassi di controllo Null del parametro non corretta. Deve essere '!!'. - - 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. @@ -782,6 +787,16 @@ 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. + + The #line directive end position must be greater than or equal to the start position La posizione finale della direttiva #line deve essere maggiore o uguale alla posizione iniziale @@ -927,6 +942,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. @@ -1057,6 +1082,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. @@ -1197,6 +1242,11 @@ è 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. Un elemento 'struct' con inizializzatori di campo deve includere un costruttore dichiarato in modo esplicito. @@ -1222,6 +1272,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. @@ -1277,6 +1342,11 @@ Non è possibile usare Seziona modelli per un valore di tipo '{0}'. + + Unterminated raw string literal. + Unterminated raw string literal. + + A generic task-like return type was expected, but the type '{0}' found in 'AsyncMethodBuilder' attribute was not suitable. It must be an unbound generic type of arity one, and its containing type (if any) must be non-generic. È previsto un tipo restituito simile a un'attività generica, ma il tipo '{0}' trovato nell'attributo 'AsyncMethodBuilder' non è idoneo. Deve essere un tipo generico non associato di grado uno e il tipo che lo contiene (se presente) deve essere non generico. @@ -1377,6 +1447,11 @@ campi posizionali nei record + + raw string literals + raw string literals + + record structs struct di record diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 2184b01594d64..8e4920c4ec36e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -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 @_:' をご使用ください。 @@ -597,6 +602,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 +642,6 @@ 'in' 修飾子を持つ引数を、動的ディスパッチされる式で使用することはできません。 - - Incorrect parameter null checking syntax. Should be '!!'. - パラメーターの null チェック構文が正しくありません。"!!" にする必要があります。 - - 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} ' 以上の言語バージョンを使用してください。 @@ -782,6 +787,16 @@ 属性を含むラムダ式は、式ツリーに変換できません + + 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. + + The #line directive end position must be greater than or equal to the start position #line ディレクティブの終了位置は、開始位置と同じかそれ以上でなければなりません @@ -927,6 +942,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}' はインスタンス メソッドではありません。レシーバーを、補間された文字列ハンドラー引数にすることはできません。 @@ -1057,6 +1082,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 に設定することをご検討ください。 @@ -1197,6 +1242,11 @@ stdin 引数 '-' が指定されていますが、入力が標準入力ストリームからリダイレクトされていません。 + + String must start with quote character: " + String must start with quote character: " + + A 'struct' with field initializers must include an explicitly declared constructor. フィールド初期化子を持つ 'struct' には、明示的に宣言されたコンストラクターを含める必要があります。 @@ -1222,6 +1272,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. トップレベルのステートメントは、名前空間および型の宣言の前にある必要があります。 @@ -1277,6 +1342,11 @@ スライス パターンは、'{0}' 型の値に使用されない可能性があります。 + + Unterminated raw string literal. + Unterminated raw string literal. + + A generic task-like return type was expected, but the type '{0}' found in 'AsyncMethodBuilder' attribute was not suitable. It must be an unbound generic type of arity one, and its containing type (if any) must be non-generic. 汎用タスクのような戻り値の型が必要ですが、'AsyncMethodBuilder' 属性で見つかった型 '{0}' が適切ではありませんでした。アリティの非バインド ジェネリック型である必要があり、それを含む型 (存在する場合) は非ジェネリックでなければなりません。 @@ -1377,6 +1447,11 @@ レコード内の位置指定フィールド + + raw string literals + raw string literals + + record structs レコード構造体 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 56fe083f974e4..02c6a1afa275d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -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 @_:'을 사용하세요. @@ -597,6 +602,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 +642,6 @@ 동적으로 디스패치된 식에서 'in' 한정자가 있는 인수를 사용할 수 없습니다. - - Incorrect parameter null checking syntax. Should be '!!'. - 잘못된 매개 변수 Null 검사 구문입니다. '!!'이어야 합니다. - - 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}'이상을 사용하세요. @@ -782,6 +787,16 @@ 특성이 있는 람다 식은 식 트리로 변환할 수 없습니다. + + 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. + + The #line directive end position must be greater than or equal to the start position #line 지시문 끝 위치는 시작 위치보다 크거나 같아야 합니다. @@ -927,6 +942,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}'은(는) 인스턴스 메서드가 아니므로 수신기는 보간된 문자열 처리기 인수가 될 수 없습니다. @@ -1057,6 +1082,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로 설정해 보세요. @@ -1197,6 +1242,11 @@ stdin 인수 '-'를 지정했지만 표준 입력 스트림에서 입력이 리디렉션되지 않았습니다. + + String must start with quote character: " + String must start with quote character: " + + A 'struct' with field initializers must include an explicitly declared constructor. 필드 이니셜라이저가 있는 '구조체'에는 명시적으로 선언된 생성자가 포함되어야 합니다. @@ -1222,6 +1272,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. 최상위 문은 네임스페이스 및 형식 선언 앞에 와야 합니다. @@ -1277,6 +1342,11 @@ 조각 패턴은 '{0}' 형식 값에 사용할 수 없습니다. + + Unterminated raw string literal. + Unterminated raw string literal. + + A generic task-like return type was expected, but the type '{0}' found in 'AsyncMethodBuilder' attribute was not suitable. It must be an unbound generic type of arity one, and its containing type (if any) must be non-generic. 일반 작업과 같은 반환 유형이 예상되었지만 'AsyncMethodBuilder' 특성에 있는 '{0}' 유형이 적합하지 않습니다. 이는 인자 수가 1인 바인딩되지 않은 제네릭 유형이어야 하고, 포함하는 유형(있는 경우)은 제네릭이 아니어야 합니다. @@ -1377,6 +1447,11 @@ 레코드의 위치 필드 + + raw string literals + raw string literals + + record structs 레코드 구조체 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 9f96d4745d092..196e705e72f15 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -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 „_”. @@ -597,6 +602,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 +642,6 @@ Nie można używać argumentów z modyfikatorem „in” w wyrażeniach przydzielanych dynamicznie. - - Incorrect parameter null checking syntax. Should be '!!'. - Niepoprawna składnia sprawdzania wartości null parametru. Powinien mieć wartość „!!". - - 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. @@ -782,6 +787,16 @@ 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. + + The #line directive end position must be greater than or equal to the start position Pozycja końcowa dyrektywy #wiersza musi być większa lub równa pozycji początkowej @@ -927,6 +942,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. @@ -1057,6 +1082,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. @@ -1197,6 +1242,11 @@ 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. Element „struct” z inicjatorami pól musi zawierać jawnie zadeklarowanego konstruktora. @@ -1222,6 +1272,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. @@ -1277,6 +1342,11 @@ Wzorców wycinków nie można używać na potrzeby wartości typu „{0}”. + + Unterminated raw string literal. + Unterminated raw string literal. + + A generic task-like return type was expected, but the type '{0}' found in 'AsyncMethodBuilder' attribute was not suitable. It must be an unbound generic type of arity one, and its containing type (if any) must be non-generic. Oczekiwano zwracanego typu podobnego do zadania ogólnego, ale typ "{0}" znaleziony w atrybucie "AsyncMethodBuilder" był nieodpowiedni. Musi to być niepowiązany typ ogólny jednego argumentu, a zawarty w nim typ (jeśli występuje), nie może być ogólny. @@ -1377,6 +1447,11 @@ pola pozycyjne w rekordach + + raw string literals + raw string literals + + record structs struktury rekordów diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index e54bd3baee10d..5d7a3f8be564c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -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 '_'. @@ -597,6 +602,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 +642,6 @@ Os argumentos com o modificador 'in' não podem ser usados em expressões vinculadas dinamicamente. - - Incorrect parameter null checking syntax. Should be '!!'. - Sintaxe de verificação de nulo de parâmetro incorreta. Deveria estar '!!'. - - 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. @@ -782,6 +787,16 @@ 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. + + The #line directive end position must be greater than or equal to the start position A posição final da diretiva #line deve ser maior ou igual à posição inicial @@ -927,6 +942,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. @@ -1057,6 +1082,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. @@ -1197,6 +1242,11 @@ 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. Uma 'estrutura' com inicializadores de campo deve incluir um construtor declarado explicitamente. @@ -1222,6 +1272,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. @@ -1277,6 +1342,11 @@ Os padrões de fatia não podem ser usados para um valor do tipo '{0}'. + + Unterminated raw string literal. + Unterminated raw string literal. + + A generic task-like return type was expected, but the type '{0}' found in 'AsyncMethodBuilder' attribute was not suitable. It must be an unbound generic type of arity one, and its containing type (if any) must be non-generic. Um tipo de retorno semelhante à tarefa genérica era esperado, mas o tipo '{0}' encontrado no atributo 'AsyncMethodBuilder' não era adequado. Ele deve ser um tipo genérico não associado de arity um e seu tipo recipiente (se houver) deve ser não genérico. @@ -1377,6 +1447,11 @@ campos posicionais nos registros + + raw string literals + raw string literals + + record structs registrar structs diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index d82f4492a76ac..5e4da7accecbc 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -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 @_:" в качестве константы "_". @@ -597,6 +602,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 +642,6 @@ Аргументы с модификатором "in" невозможно использовать в динамически диспетчеризируемых выражениях. - - Incorrect parameter null checking syntax. Should be '!!'. - Неправильный синтаксис проверки значений NULL для параметра. Следует использовать "!!". - - 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}" или более позднюю. @@ -782,6 +787,16 @@ Невозможно преобразовать лямбда-выражение с атрибутами в дерево выражения + + 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. + + The #line directive end position must be greater than or equal to the start position Позиция окончания директивы #line должна больше или равна позиции начала @@ -927,6 +942,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}" не является методом экземпляра, получатель не может быть аргументом обработчика интерполированных строк. @@ -1057,6 +1082,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 (ложь). @@ -1197,6 +1242,11 @@ Указан аргумент stdin "-", но входные данные не были перенаправлены из стандартного входного потока. + + String must start with quote character: " + String must start with quote character: " + + A 'struct' with field initializers must include an explicitly declared constructor. Параметр struct с инициализаторами полей должен включать явно объявленный конструктор. @@ -1222,6 +1272,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. Инструкции верхнего уровня должны предшествовать объявлениям пространств имен и типов. @@ -1277,6 +1342,11 @@ Шаблоны среза не могут использоваться для значений типа "{0}". + + Unterminated raw string literal. + Unterminated raw string literal. + + A generic task-like return type was expected, but the type '{0}' found in 'AsyncMethodBuilder' attribute was not suitable. It must be an unbound generic type of arity one, and its containing type (if any) must be non-generic. Ожидался универсальный возвращаемый тип, схожий с задачей, но тип "{0}", обнаруженный в атрибуте "AsyncMethodBuilder", не подходит. Требуется неограниченный универсальный тип c арностью 1, а его содержащий тип (если есть) не должен быть универсальным @@ -1377,6 +1447,11 @@ позиционные поля в записях + + raw string literals + raw string literals + + record structs структуры записей diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 3e64ce4e66c7b..96705aed73f17 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -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. @@ -597,6 +602,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 +642,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 '!!'. - Yanlış parametre null denetimi söz dizimi. “!!” olmalıdır. - - 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. @@ -782,6 +787,16 @@ Ö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. + + The #line directive end position must be greater than or equal to the start position #line yönergesi bitiş konumu başlangıç konumundan büyük veya buna eşit olmalıdır @@ -927,6 +942,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. @@ -1057,6 +1082,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. @@ -1197,6 +1242,11 @@ '-' 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. Alan başlatıcılarına sahip bir 'struct' açıkça bildirilen bir oluşturucu içermelidir. @@ -1222,6 +1272,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. @@ -1277,6 +1342,11 @@ Dilim desenleri, '{0}' türünde bir değer için kullanılamaz. + + Unterminated raw string literal. + Unterminated raw string literal. + + A generic task-like return type was expected, but the type '{0}' found in 'AsyncMethodBuilder' attribute was not suitable. It must be an unbound generic type of arity one, and its containing type (if any) must be non-generic. Genel bir görev benzeri dönüş türü bekleniyordu, ancak ' AsyncMethodBuilder ' özniteliğinde bulunan '{0}' türü uygun değildi. İlişkisiz bir genel tür olması ve içeren türü (varsa) genel olmayan olması gerekir. @@ -1377,6 +1447,11 @@ kayıtlardaki konumsal alanlar + + raw string literals + raw string literals + + record structs kayıt yapıları diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 7bb00b0d32b31..d9a0d08a783b2 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -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 @_:”以定义名为“_”的变量。 @@ -597,6 +602,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 +642,6 @@ 带有 "in" 修饰符的参数不能用于动态调度的表达式。 - - Incorrect parameter null checking syntax. Should be '!!'. - 参数 null 检查语法不正确。应为 "!!"。 - - 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}’ 或更高版本。 @@ -782,6 +787,16 @@ 无法将具有属性的 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. + + The #line directive end position must be greater than or equal to the start position #Line 指令结束位置必须大于或等于起始位置 @@ -927,6 +942,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}”不是实例方法,接收器不能是内插字符串处理程序参数。 @@ -1057,6 +1082,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。 @@ -1197,6 +1242,11 @@ 已指定 stdin 参数 "-",但尚未从标准输入流重定向输入。 + + String must start with quote character: " + String must start with quote character: " + + A 'struct' with field initializers must include an explicitly declared constructor. 具有字段初始值设定项的“结构”必须包含显式声明的构造函数。 @@ -1222,6 +1272,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. 顶级语句必须位于命名空间和类型声明之前。 @@ -1277,6 +1342,11 @@ 切片模式不能用于类型为“{0}”的值。 + + Unterminated raw string literal. + Unterminated raw string literal. + + A generic task-like return type was expected, but the type '{0}' found in 'AsyncMethodBuilder' attribute was not suitable. It must be an unbound generic type of arity one, and its containing type (if any) must be non-generic. 应为泛用类任务返回类型,但在“AsyncMethodBuilder”属性中发现的类型“{0}”不合适。它必须是 arity one 的未绑定泛型类型,并且其包含类型(如果有)必须为非泛用。 @@ -1377,6 +1447,11 @@ 记录中的位置字段 + + raw string literals + raw string literals + + record structs 记录结构 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index b5e0be75daeab..551b2ed6161a4 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -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 @_:'。 @@ -597,6 +602,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 +642,6 @@ 具有 'in' 修飾元的引數不可用於動態分派的運算式。 - - Incorrect parameter null checking syntax. Should be '!!'. - 檢查參數是否為 Null 的語法不正確。應為 '!!'。 - - 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}' 或更高的語言版本。 @@ -782,6 +787,16 @@ 具有屬性的 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. + + The #line directive end position must be greater than or equal to the start position #Line 指示詞結束位置必須大於或等於開始位置 @@ -927,6 +942,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}' 不是執行個體方法,接收器不可為差補字串處理常式引數。 @@ -1057,6 +1082,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。 @@ -1197,6 +1242,11 @@ 已指定 stdin 引數 '-',但尚未從標準輸入資料流重新導向輸入。 + + String must start with quote character: " + String must start with quote character: " + + A 'struct' with field initializers must include an explicitly declared constructor. 具有欄位初始設定式的 'struct' 必須包含明確宣告的建構函式。 @@ -1222,6 +1272,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. 最上層陳述式必須在命名空間和型別宣告之前。 @@ -1277,6 +1342,11 @@ 類型 '{0}' 的值不可使用切片模式。 + + Unterminated raw string literal. + Unterminated raw string literal. + + A generic task-like return type was expected, but the type '{0}' found in 'AsyncMethodBuilder' attribute was not suitable. It must be an unbound generic type of arity one, and its containing type (if any) must be non-generic. 應存在類似泛型工作的傳回型別,但在 'AsyncMethodBuilder' 屬性中找到的類型 '{0}' 不適用。它必須是 arity one 的未綁定泛型型別,並且其包含類型 (如果有) 必須是非泛型。 @@ -1377,6 +1447,11 @@ 記錄中的位置欄位 + + raw string literals + raw string literals + + record structs 記錄結構 diff --git a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs index 8e38f5de7ff54..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); } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs index 59e075cdefb02..0781f26060308 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenAsyncIteratorTests.cs @@ -176,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) @@ -193,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 @@ -261,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 { @@ -274,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 }"); } @@ -343,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) @@ -360,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 @@ -409,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 { @@ -422,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 }"); } @@ -2569,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, @@ -2598,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 @@ -2635,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"" @@ -2664,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 @@ -2674,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 { @@ -2689,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, @@ -2751,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 @@ -2784,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"" @@ -2811,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 @@ -2821,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 { @@ -2835,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); } } @@ -2974,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, @@ -2999,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 @@ -3033,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"" @@ -3057,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 @@ -3068,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 { @@ -3087,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); } @@ -3236,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, @@ -3261,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 @@ -3295,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"" @@ -3319,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 @@ -3330,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 { @@ -3349,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); } @@ -3499,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, @@ -3524,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 @@ -3558,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"" @@ -3582,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 @@ -3593,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 { @@ -3612,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); } @@ -3716,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, @@ -3741,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 @@ -3771,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"" @@ -3795,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 @@ -3806,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 { @@ -3825,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); } @@ -7987,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/Emit/CompilationEmitTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs index 0683a48eedec3..58eda81e723ad 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() { diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_WellKnownAttributes.cs index b472499f4a267..4db1f333beb88 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_WellKnownAttributes.cs @@ -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/Emit2/Attributes/InternalsVisibleToAndStrongNameTests.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/InternalsVisibleToAndStrongNameTests.cs index ba775a35557ac..96a08399ae52c 100644 --- a/src/Compilers/CSharp/Test/Emit2/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/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 2d8f814c0a653..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; @@ -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/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/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/FunctionPointerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs index 8d653afb5bfbc..8da853f551111 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() { 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/InterpolationTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InterpolationTests.cs index a16e9b0f973a1..bb0b85555896f 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] @@ -3978,6 +3977,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 +9339,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), @@ -9515,6 +9649,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/NullCheckedParameterTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullCheckedParameterTests.cs index 66aa80df46fd6..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] diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index db0cf4d79fbdc..522c906b2ca33 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -20427,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() { @@ -39289,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 = @" @@ -39311,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!; } @@ -39322,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] @@ -64246,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] @@ -68209,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[] { @" @@ -68253,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) ); } @@ -68850,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 = @" @@ -68868,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] @@ -87030,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 } } @@ -87039,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(); } @@ -87219,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?")] 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/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..495602792f55a 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_ListPatterns.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests_ListPatterns.cs @@ -230,6 +230,207 @@ .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; + } +} +"; + var verifier = CompileAndVerify(new[] { source, TestSources.Index, TestSources.Range }, parseOptions: TestOptions.RegularWithListPatterns, options: TestOptions.ReleaseDll).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 +1582,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() { @@ -3853,14 +4081,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 +4096,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 +4111,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 +4150,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 +4217,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 +4232,7 @@ public void M() rest4 = null; } else - rest4.ToString(); // 8, 9 + rest4.ToString(); // 6, 7 } } "; @@ -3975,29 +4241,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 +4956,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 +5023,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) ); } @@ -6178,45 +6429,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 +6938,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 +6986,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 +7016,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() { @@ -7974,7 +8308,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 +8316,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..48a73d6f5e804 --- /dev/null +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RawInterpolationTests_Handler.cs @@ -0,0 +1,13470 @@ +// Licensed to the .NET Foundation under one or more 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); + var verifier = CompileAndVerify(comp, expectedOutput: @" +value:S converted +value:C"); + + 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); + + var verifier = CompileAndVerify( + new[] { code, InterpolatedStringHandlerArgumentAttribute, handler }, + expectedOutput: "1literal:literal", + symbolValidator: validator, + sourceSymbolValidator: validator, + verify: ExecutionConditionUtil.IsMonoOrCoreClr ? Verification.Passes : 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/TargetTypedDefaultTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/TargetTypedDefaultTests.cs index ebf0618a26854..a2ebe9d27a909 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() 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/SourceGeneration/GeneratorDriverTests.cs b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs index 52a594701e739..e191d0b9fbcda 100644 --- a/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverTests.cs @@ -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/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/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/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/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/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/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/SyntaxNormalizerTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs index e85842637d214..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() 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/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/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/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 2245042f57874..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); @@ -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/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/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/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/FatalError.cs b/src/Compilers/Core/Portable/InternalUtilities/FatalError.cs index 6007023687490..92d5741a69472 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 @@ -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/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 87c5b2a600c03..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); @@ -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/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 b780b1cd315e8..745c6f1fb06c3 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -1,43 +1,5 @@ -*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.IOperation.ChildOperations.get -> Microsoft.CodeAnalysis.IOperation.OperationList Microsoft.CodeAnalysis.IOperation.OperationList Microsoft.CodeAnalysis.IOperation.OperationList.Any() -> bool @@ -63,185 +25,6 @@ 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 -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.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! +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! -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? 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 a7978b68a651f..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; 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/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 a9f22745e31da..7cdcdded82c88 100644 --- a/src/Compilers/Test/Core/Assert/AssertEx.cs +++ b/src/Compilers/Test/Core/Assert/AssertEx.cs @@ -927,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 eb5540293804f..cd7763756c98c 100644 --- a/src/Compilers/Test/Core/CommonTestBase.cs +++ b/src/Compilers/Test/Core/CommonTestBase.cs @@ -46,6 +46,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 +71,7 @@ internal CompilationVerifier CompileAndVerifyCommon( manifestResources, expectedSignatures, expectedOutput, + trimOutput, expectedReturnCode, args ?? Array.Empty(), assemblyValidator, @@ -142,6 +144,7 @@ internal CompilationVerifier Emit( IEnumerable manifestResources, SignatureDescription[] expectedSignatures, string expectedOutput, + bool trimOutput, int? expectedReturnCode, string[] args, Action assemblyValidator, @@ -151,7 +154,7 @@ 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) { diff --git a/src/Compilers/Test/Core/Compilation/IRuntimeEnvironment.cs b/src/Compilers/Test/Core/Compilation/IRuntimeEnvironment.cs index faf86ba2a4501..00fc3c69f29cc 100644 --- a/src/Compilers/Test/Core/Compilation/IRuntimeEnvironment.cs +++ b/src/Compilers/Test/Core/Compilation/IRuntimeEnvironment.cs @@ -387,7 +387,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/CompilationVerifier.cs b/src/Compilers/Test/Core/CompilationVerifier.cs index 1ed62d8b828c8..c66e28937356d 100644 --- a/src/Compilers/Test/Core/CompilationVerifier.cs +++ b/src/Compilers/Test/Core/CompilationVerifier.cs @@ -196,7 +196,15 @@ 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); @@ -211,7 +219,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) { 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/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/Platform/CoreClr/CoreCLRRuntimeEnvironment.cs b/src/Compilers/Test/Core/Platform/CoreClr/CoreCLRRuntimeEnvironment.cs index f8935f6337a90..43251be80d894 100644 --- a/src/Compilers/Test/Core/Platform/CoreClr/CoreCLRRuntimeEnvironment.cs +++ b/src/Compilers/Test/Core/Platform/CoreClr/CoreCLRRuntimeEnvironment.cs @@ -77,18 +77,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"); diff --git a/src/Compilers/Test/Core/Platform/Desktop/DesktopRuntimeEnvironment.cs b/src/Compilers/Test/Core/Platform/Desktop/DesktopRuntimeEnvironment.cs index 87285a50330f5..bb26095e369d7 100644 --- a/src/Compilers/Test/Core/Platform/Desktop/DesktopRuntimeEnvironment.cs +++ b/src/Compilers/Test/Core/Platform/Desktop/DesktopRuntimeEnvironment.cs @@ -235,7 +235,7 @@ 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 { @@ -243,10 +243,13 @@ public int Execute(string moduleName, string[] args, string expectedOutput) emitData.RuntimeData.ExecuteRequested = true; var resultCode = emitData.Manager.Execute(moduleName, args, 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; 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 444e63dd244b1..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"; @@ -296,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); @@ -306,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 1b78800f91fbb..7ec96c09388a9 100644 --- a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs @@ -655,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, @@ -671,6 +672,7 @@ internal CompilationVerifier CompileAndVerifyWithMscorlib40( symbolValidator, expectedSignatures, expectedOutput, + trimOutput, expectedReturnCode, args, options, @@ -689,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, @@ -705,6 +708,7 @@ internal CompilationVerifier CompileAndVerifyWithMscorlib46( symbolValidator, expectedSignatures, expectedOutput, + trimOutput, expectedReturnCode, args, options, @@ -724,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, @@ -744,6 +749,7 @@ internal CompilationVerifier CompileAndVerifyExperimental( symbolValidator, expectedSignatures, expectedOutput, + trimOutput, expectedReturnCode, args, options, @@ -763,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, @@ -779,6 +786,7 @@ internal CompilationVerifier CompileAndVerifyWithWinRt( symbolValidator, expectedSignatures, expectedOutput, + trimOutput, expectedReturnCode, args, options, @@ -797,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, @@ -813,6 +822,7 @@ internal CompilationVerifier CompileAndVerifyWithCSharp( symbolValidator, expectedSignatures, expectedOutput, + trimOutput, expectedReturnCode, args, options, @@ -831,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, @@ -850,6 +861,7 @@ internal CompilationVerifier CompileAndVerify( symbolValidator, expectedSignatures, expectedOutput, + trimOutput, expectedReturnCode, args, emitOptions, @@ -865,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, @@ -891,6 +904,7 @@ Action translate(Action action) translate(symbolValidator), expectedSignatures, expectedOutput, + trimOutput, expectedReturnCode, args, emitOptions, @@ -915,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)); } @@ -1440,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/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/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/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/Emit/CompilationEmitTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/CompilationEmitTests.vb index bf050def0c3cf..8d857b7525507 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/CompilationEmitTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/CompilationEmitTests.vb @@ -238,7 +238,6 @@ BC30451: 'NoSuchMethod' is not declared. It may be inaccessible due to its prote 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 = " 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/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/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/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/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..5620106d358f3 --- /dev/null +++ b/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_Return.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.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 (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..f724778bc6692 --- /dev/null +++ b/src/EditorFeatures/CSharp/RawStringLiteral/RawStringLiteralCommandHandler_TypeChar.cs @@ -0,0 +1,237 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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) ?? + RawStringLiteralCommandHandler.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/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/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..05171cee84a20 100644 --- a/src/EditorFeatures/CSharpTest/BraceHighlighting/BraceHighlightingTests.cs +++ b/src/EditorFeatures/CSharpTest/BraceHighlighting/BraceHighlightingTests.cs @@ -446,5 +446,47 @@ 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 TestUnmatchedJsonBracket1() + { + var input = @" +class C +{ + void Goo() + { + var r = /*lang=json*/ @""new Json$$(1, 2, 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..dcfcda77df3ad 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 @@ -3447,6 +3446,119 @@ 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 TestIncompleteRegexLeadingToStringInsideSkippedTokensInsideADirective(TestHost testHost) @@ -3477,6 +3589,191 @@ 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 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 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..e35789c2a8a28 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); } 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/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/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_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..c638c5a3c6904 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 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/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/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/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/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/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..cc95f9c181ea2 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/EmbeddedLanguages/JsonStringDetectorTests.cs @@ -0,0 +1,71 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading.Tasks; +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(); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/EmbeddedLanguages/ValidateJsonStringTests.cs b/src/EditorFeatures/CSharpTest/EmbeddedLanguages/ValidateJsonStringTests.cs new file mode 100644 index 0000000000000..20b424062f905 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/EmbeddedLanguages/ValidateJsonStringTests.cs @@ -0,0 +1,337 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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 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} + + +"); + } + } +} 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 07c98c2a46c2c..8f88801a7f0c7 100644 --- a/src/EditorFeatures/CSharpTest/ExtractClass/ExtractClassTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractClass/ExtractClassTests.cs @@ -7,6 +7,7 @@ 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; @@ -691,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(); } @@ -758,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(); } @@ -811,7 +812,7 @@ static void Main(string[] args) }, LanguageVersion = LanguageVersion.CSharp10, Options = { - { CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, CodeAnalysis.AddImports.AddImportPlacement.InsideNamespace } + { CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, AddImportPlacement.InsideNamespace } } }.RunAsync(); } @@ -879,7 +880,7 @@ static void Main(string[] args) }, LanguageVersion = LanguageVersion.CSharp10, Options = { - { CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, CodeAnalysis.AddImports.AddImportPlacement.InsideNamespace } + { CSharpCodeStyleOptions.PreferredUsingDirectivePlacement, AddImportPlacement.InsideNamespace } } }.RunAsync(); } 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 f13b856096bac..1808b63078880 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/FormattingEngineTests.cs @@ -10,6 +10,7 @@ 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; @@ -2193,7 +2194,7 @@ class Test using var workspace = new AdhocWorkspace(); - var options = SyntaxFormattingOptions.Default; + var options = CSharpSyntaxFormattingOptions.Default; var formattedRoot = Formatter.Format(root, workspace.Services, options, CancellationToken.None); var annotatedTrivia = formattedRoot.GetAnnotatedTrivia("marker"); 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/InitializeParameter/AddParameterCheckTests.cs b/src/EditorFeatures/CSharpTest/InitializeParameter/AddParameterCheckTests.cs index bc510b2c65bb2..2f1327b4fb05a 100644 --- a/src/EditorFeatures/CSharpTest/InitializeParameter/AddParameterCheckTests.cs +++ b/src/EditorFeatures/CSharpTest/InitializeParameter/AddParameterCheckTests.cs @@ -1684,6 +1684,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() 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..ac5f4e8a5ebad 100644 --- a/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs +++ b/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs @@ -1504,6 +1504,25 @@ 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")); +}); + } } } #pragma warning restore CS0618 // MatchKind is obsolete 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 2cd00a5147754..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() @@ -8114,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..1110ca63d75f5 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/RawStringLiteral/RawStringLiteralCommandHandlerTests.cs @@ -0,0 +1,349 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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 = $""""""""$$"""""); + } + + #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 + } +} 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 b0bd2e9644e56..c44723ac7b064 100644 --- a/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs +++ b/src/EditorFeatures/CSharpTest/SplitStringLiteral/SplitStringLiteralCommandHandlerTests.cs @@ -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/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/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/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/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/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/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/EditorFeaturesResources.resx b/src/EditorFeatures/Core/EditorFeaturesResources.resx index ee32fef772903..8703e1b15dcdd 100644 --- a/src/EditorFeatures/Core/EditorFeaturesResources.resx +++ b/src/EditorFeatures/Core/EditorFeaturesResources.resx @@ -942,9 +942,6 @@ Do you want to proceed? Get help for '{0}' - - Get help for '{0}' from Bing - Gathering Suggestions - '{0}' @@ -1051,4 +1048,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..7c7d2edfa2d86 --- /dev/null +++ b/src/EditorFeatures/Core/EmbeddedLanguages/Json/JsonEmbeddedBraceMatcher.cs @@ -0,0 +1,106 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.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); + var tree = detector.TryParseString(token, semanticModel, 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/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/IVSTypeScriptFindUsagesContext.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptFindUsagesContext.cs index cee552048774a..1b49a61971ab1 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptFindUsagesContext.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/IVSTypeScriptFindUsagesContext.cs @@ -2,9 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.FindUsages; namespace Microsoft.CodeAnalysis.ExternalAccess.VSTypeScript.Api { @@ -28,6 +30,8 @@ internal interface IVSTypeScriptFindUsagesContext ValueTask OnDefinitionFoundAsync(VSTypeScriptDefinitionItem definition, CancellationToken cancellationToken); ValueTask OnReferenceFoundAsync(VSTypeScriptSourceReferenceItem reference, CancellationToken cancellationToken); + + ValueTask OnCompletedAsync(CancellationToken cancellationToken); } internal interface IVSTypeScriptStreamingProgressTracker @@ -36,8 +40,29 @@ internal interface IVSTypeScriptStreamingProgressTracker ValueTask ItemCompletedAsync(CancellationToken cancellationToken); } - internal class VSTypeScriptDefinitionItem + internal sealed class VSTypeScriptDefinitionItem { + internal readonly DefinitionItem UnderlyingObject; + + internal VSTypeScriptDefinitionItem(DefinitionItem underlyingObject) + => UnderlyingObject = underlyingObject; + + public static VSTypeScriptDefinitionItem Create( + ImmutableArray tags, + ImmutableArray displayParts, + ImmutableArray sourceSpans, + ImmutableArray nameDisplayParts = default, + bool displayIfNoReferences = true) + { + return new(DefinitionItem.Create( + tags, displayParts, sourceSpans.SelectAsArray(span => span.ToDocumentSpan()), nameDisplayParts, + properties: null, displayableProperties: ImmutableDictionary.Empty, displayIfNoReferences: displayIfNoReferences)); + } + + public static VSTypeScriptDefinitionItem Create(VSTypeScriptDefinitionItemBase item) + => new(item); + + [Obsolete] public VSTypeScriptDefinitionItem( ImmutableArray tags, ImmutableArray displayParts, @@ -47,38 +72,77 @@ public VSTypeScriptDefinitionItem( ImmutableDictionary? displayableProperties = null, bool displayIfNoReferences = true) { - Tags = tags; - DisplayParts = displayParts; - SourceSpans = sourceSpans; - NameDisplayParts = nameDisplayParts; - Properties = properties; - DisplayableProperties = displayableProperties; - DisplayIfNoReferences = displayIfNoReferences; + UnderlyingObject = new DefinitionItem.DefaultDefinitionItem( + tags, displayParts, nameDisplayParts, originationParts: ImmutableArray.Empty, sourceSpans, properties, displayableProperties, 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 ImmutableArray Tags => UnderlyingObject.Tags; + public ImmutableArray DisplayParts => UnderlyingObject.DisplayParts; + + [Obsolete] + public ImmutableArray SourceSpans => UnderlyingObject.SourceSpans; + + 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, showInPreviewTab, activateTab, cancellationToken); } - internal class VSTypeScriptSourceReferenceItem + internal sealed class VSTypeScriptSourceReferenceItem { + internal readonly SourceReferenceItem UnderlyingObject; + + public VSTypeScriptSourceReferenceItem( + VSTypeScriptDefinitionItem definition, + VSTypeScriptDocumentSpan sourceSpan, + VSTypeScriptSymbolUsageInfo symbolUsageInfo) + { + UnderlyingObject = new SourceReferenceItem(definition.UnderlyingObject, sourceSpan.ToDocumentSpan(), symbolUsageInfo.UnderlyingObject); + } + + [Obsolete] public VSTypeScriptSourceReferenceItem( VSTypeScriptDefinitionItem definition, DocumentSpan sourceSpan, SymbolUsageInfo symbolUsageInfo) { - Definition = definition; - SourceSpan = sourceSpan; - SymbolUsageInfo = symbolUsageInfo; + UnderlyingObject = new SourceReferenceItem(definition.UnderlyingObject, sourceSpan, symbolUsageInfo); } - public VSTypeScriptDefinitionItem Definition { get; } - public DocumentSpan SourceSpan { get; } - public SymbolUsageInfo SymbolUsageInfo { get; } + public VSTypeScriptDocumentSpan GetSourceSpan() + => new(UnderlyingObject.SourceSpan); + + [Obsolete] + public DocumentSpan SourceSpan + => 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/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/VSTypeScriptDocumentSpan.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptDocumentSpan.cs index 2af32609217b3..9aa9cc2e5a526 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptDocumentSpan.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/VSTypeScriptDocumentSpan.cs @@ -18,5 +18,13 @@ 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/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/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..12b090b4f3bb4 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptFindUsagesService.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptFindUsagesService.cs @@ -3,8 +3,8 @@ // 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; @@ -12,11 +12,12 @@ 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; @@ -28,22 +29,22 @@ public VSTypeScriptFindUsagesService(IVSTypeScriptFindUsagesService underlyingSe } public Task FindReferencesAsync(Document document, int position, IFindUsagesContext context, CancellationToken cancellationToken) - => _underlyingService.FindReferencesAsync(document, position, new VSTypeScriptFindUsagesContext(context), 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); + => _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 +52,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/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/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/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/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/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/CodeActions/CodeActionOptionsStorage.cs b/src/EditorFeatures/Core/Implementation/CodeActions/CodeActionOptionsStorage.cs new file mode 100644 index 0000000000000..7680a3a552668 --- /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( + IsBlocking: isBlocking, + SearchReferenceAssemblies: globalOptions.GetOption(SymbolSearchOptions.SuggestForTypesInReferenceAssemblies, language), + HideAdvancedMembers: globalOptions.GetOption(CompletionOptionsStorage.HideAdvancedMembers, language)); + } +} 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/EditAndContinue/EditAndContinueLanguageService.cs b/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueLanguageService.cs index 707ce22218021..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)) { 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/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..a5f64ee245507 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/CompletionSource.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/CompletionSource.cs @@ -49,10 +49,10 @@ internal sealed class CompletionSource : ForegroundThreadAffinitizedObject, IAsy internal const string TypeImportCompletionEnabled = nameof(TypeImportCompletionEnabled); internal const string TargetTypeFilterExperimentEnabled = nameof(TargetTypeFilterExperimentEnabled); - 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 = @@ -112,13 +112,13 @@ 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)); // 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. @@ -184,7 +184,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 +222,7 @@ private bool TryInvokeSnippetCompletion( return true; } - public Task GetCompletionContextAsync( + public async Task GetCompletionContextAsync( IAsyncCompletionSession session, AsyncCompletionData.CompletionTrigger trigger, SnapshotPoint triggerLocation, @@ -232,7 +232,14 @@ 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 AsyncCompletionData.CompletionContext.Empty; + } + + var options = _globalOptions.GetCompletionOptions(document.Project.Language); + return await GetCompletionContextWorkerAsync(document, session, trigger, triggerLocation, options, cancellationToken).ConfigureAwait(false); } public async Task GetExpandedCompletionContextAsync( @@ -246,38 +253,33 @@ 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); + + 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 + }; + + return await GetCompletionContextWorkerAsync(document, session, intialTrigger, initialTriggerLocation, options, cancellationToken).ConfigureAwait(false); + } } return AsyncCompletionData.CompletionContext.Empty; } private async Task GetCompletionContextWorkerAsync( + Document document, IAsyncCompletionSession session, 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,43 +289,40 @@ 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(); + var itemsBuilder = new ArrayBuilder(completionList.Items.Length); - 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 itemsBuilder = new ArrayBuilder(completionList.Items.Length); - foreach (var roslynItem in completionList.Items) - { - cancellationToken.ThrowIfCancellationRequested(); - var item = Convert(document, roslynItem, filterSet, triggerLocation); - itemsBuilder.Add(item); - } - items = itemsBuilder.ToImmutableAndFree(); + AddPropertiesToSession(session, completionList, triggerLocation); + + var filters = filterSet.GetFilterStatesInSet(); + var 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; + if (completionList.SuggestionModeItem is null) + return new(items, suggestionItemOptions: null, selectionHint: AsyncCompletionData.InitialSelectionHint.RegularSelection, filters); + 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); + + 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. @@ -334,7 +333,7 @@ private bool TryInvokeSnippetCompletion( // If there are suggestionItemOptions, then later HandleNormalFiltering should set selection to SoftSelection. if (!session.Properties.TryGetProperty(HasSuggestionItemOptions, out bool hasSuggestionItemOptionsBefore) || !hasSuggestionItemOptionsBefore) { - session.Properties[HasSuggestionItemOptions] = suggestionItemOptions != null; + session.Properties[HasSuggestionItemOptions] = completionList.SuggestionModeItem != null; } var excludedCommitCharacters = GetExcludedCommitCharacters(completionList.Items); @@ -347,26 +346,17 @@ private bool TryInvokeSnippetCompletion( session.Properties[ExcludedCommitCharacters] = excludedCommitCharacters; } - } - // We need to remember the trigger location for when a completion service claims expanded items are available - // since the initial trigger we are able to get from IAsyncCompletionSession might not be the same (e.g. in projection scenarios) - // 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) - { - session.Properties[ExpandedItemTriggerLocation] = triggerLocation; + // We need to remember the trigger location for when a completion service claims expanded items are available + // since the initial trigger we are able to get from IAsyncCompletionSession might not be the same (e.g. in projection scenarios) + // 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 (!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 +380,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 +404,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 +441,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..b4ad79c25b9f1 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(); - // 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) { @@ -195,16 +188,6 @@ public ImmutableArray GetFilterStatesInSet(bool addUn return builder.ToImmutableAndFree(); } - private readonly struct FilterWithMask - { - public readonly CompletionFilter Filter; - public readonly int Mask; - - public FilterWithMask(CompletionFilter filter, int mask) - { - Filter = filter; - Mask = mask; - } - } + private readonly record struct FilterWithMask(CompletionFilter Filter, int Mask); } } 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/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 ca5745d051202..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,10 +228,10 @@ 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( 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/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/InheritanceMargin/InheritanceMarginServiceHelpers.cs b/src/EditorFeatures/Core/InheritanceMargin/InheritanceMarginServiceHelpers.cs index 875b49ff4f9bb..50ab3ce9d4387 100644 --- a/src/EditorFeatures/Core/InheritanceMargin/InheritanceMarginServiceHelpers.cs +++ b/src/EditorFeatures/Core/InheritanceMargin/InheritanceMarginServiceHelpers.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.InheritanceMargin { @@ -219,6 +220,7 @@ private static async ValueTask CreateInherita { var baseSymbolItems = await baseSymbols .SelectAsArray(symbol => symbol.OriginalDefinition) + .WhereAsArray(IsNavigableSymbol) .Distinct() .SelectAsArrayAsync((symbol, _) => CreateInheritanceItemAsync( solution, @@ -229,6 +231,7 @@ private static async ValueTask CreateInherita var derivedTypeItems = await derivedTypesSymbols .SelectAsArray(symbol => symbol.OriginalDefinition) + .WhereAsArray(IsNavigableSymbol) .Distinct() .SelectAsArrayAsync((symbol, _) => CreateInheritanceItemAsync(solution, symbol, @@ -252,6 +255,7 @@ private static async ValueTask CreateInherita { var implementedMemberItems = await implementingMembers .SelectAsArray(symbol => symbol.OriginalDefinition) + .WhereAsArray(IsNavigableSymbol) .Distinct() .SelectAsArrayAsync((symbol, _) => CreateInheritanceItemAsync( solution, @@ -278,6 +282,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 +292,7 @@ private static async ValueTask CreateInherita var derivedTypeItems = await derivedTypesSymbols .SelectAsArray(symbol => symbol.OriginalDefinition) + .WhereAsArray(IsNavigableSymbol) .Distinct() .SelectAsArrayAsync((symbol, _) => CreateInheritanceItemAsync(solution, symbol, @@ -312,6 +318,7 @@ private static async ValueTask CreateInherita { var implementedMemberItems = await implementedMembers .SelectAsArray(symbol => symbol.OriginalDefinition) + .WhereAsArray(IsNavigableSymbol) .Distinct() .SelectAsArrayAsync((symbol, _) => CreateInheritanceItemAsync( solution, @@ -321,6 +328,7 @@ private static async ValueTask CreateInherita var overridenMemberItems = await overriddenMembers .SelectAsArray(symbol => symbol.OriginalDefinition) + .WhereAsArray(IsNavigableSymbol) .Distinct() .SelectAsArrayAsync((symbol, _) => CreateInheritanceItemAsync( solution, @@ -330,6 +338,7 @@ private static async ValueTask CreateInherita var overridingMemberItems = await overridingMembers .SelectAsArray(symbol => symbol.OriginalDefinition) + .WhereAsArray(IsNavigableSymbol) .Distinct() .SelectAsArrayAsync((symbol, _) => CreateInheritanceItemAsync( solution, @@ -354,9 +363,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 +496,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/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..24c3a2ce0a871 100644 --- a/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj +++ b/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj @@ -22,6 +22,7 @@ + @@ -106,6 +107,10 @@ + + + + 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/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/xlf/EditorFeaturesResources.cs.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf index 79f8eb44fde8c..52a8495df8ade 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.cs.xlf @@ -77,11 +77,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}. @@ -152,6 +147,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 diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf index 348967208ed37..80811b9b21d5e 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.de.xlf @@ -77,11 +77,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}" @@ -152,6 +147,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 diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf index 3b22bba522e45..caeff60ff6c19 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.es.xlf @@ -77,11 +77,6 @@ Obtener ayuda para "{0}" - - Get help for '{0}' from Bing - Obtener ayuda para "{0}" en Bing - - Gathering Suggestions - '{0}' Recopilando sugerencias: "{0}" @@ -152,6 +147,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 diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf index 777f9725bfb00..cc3e8fd3d9a07 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.fr.xlf @@ -77,11 +77,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}' @@ -152,6 +147,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 diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf index ac1778cf4da9f..2529637ced4f8 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.it.xlf @@ -77,11 +77,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}' @@ -152,6 +147,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 diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf index be6922c51846d..9a39e63603782 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ja.xlf @@ -77,11 +77,6 @@ '{0}' のヘルプの表示 - - Get help for '{0}' from Bing - Bing から '{0}' のヘルプを表示します - - Gathering Suggestions - '{0}' 提案を収集しています - '{0}' @@ -152,6 +147,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 キーワード - コントロール diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf index 6dab354d27f5b..ec4599726565d 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ko.xlf @@ -77,11 +77,6 @@ '{0}'에 대한 도움 받기 - - Get help for '{0}' from Bing - Bing에서 '{0}'에 대한 도움 받기 - - Gathering Suggestions - '{0}' 제안을 수집하는 중 - '{0}' @@ -152,6 +147,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 키워드 - 제어 diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf index 31063335e563e..2dd83f04669f8 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pl.xlf @@ -77,11 +77,6 @@ Uzyskaj pomoc dla „{0}” - - Get help for '{0}' from Bing - Uzyskaj pomoc dla „{0}” z wyszukiwarki Bing - - Gathering Suggestions - '{0}' Zbieranie sugestii — „{0}” @@ -152,6 +147,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 diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf index 731d833582e99..ff83385d02eee 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.pt-BR.xlf @@ -77,11 +77,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}' @@ -152,6 +147,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 diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf index babcf45cc47fa..1b413fbbd6a38 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.ru.xlf @@ -77,11 +77,6 @@ Получить справку для "{0}" - - Get help for '{0}' from Bing - Получить справку для "{0}" из системы Bing - - Gathering Suggestions - '{0}' Сбор предложений — "{0}" @@ -152,6 +147,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 Ключевое слово — управление diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf index 8fdce2e6b39f8..27c4ca463db85 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.tr.xlf @@ -77,11 +77,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}' @@ -152,6 +147,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 diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf index 36d9b80f798f2..8eaae5aff0679 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hans.xlf @@ -77,11 +77,6 @@ 获取有关“{0}”的帮助 - - Get help for '{0}' from Bing - 从必应获取有关“{0}”的帮助 - - Gathering Suggestions - '{0}' 正在收集建议 -“{0}” @@ -152,6 +147,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 关键字-控制 diff --git a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf index 63c30658352eb..9430e54dc00d6 100644 --- a/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf +++ b/src/EditorFeatures/Core/xlf/EditorFeaturesResources.zh-Hant.xlf @@ -77,11 +77,6 @@ 取得 '{0}' 的說明 - - Get help for '{0}' from Bing - 從 Bing 取得 '{0}' 的說明 - - Gathering Suggestions - '{0}' 正在蒐集建議 - '{0}' @@ -152,6 +147,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 關鍵字 - 控制項 diff --git a/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs b/src/EditorFeatures/DiagnosticsTestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs index 255c1149b57f6..8192887e6048b 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) @@ -379,7 +385,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 +425,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..70647df757344 100644 --- a/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractDiagnosticProviderBasedUserDiagnosticTest.cs +++ b/src/EditorFeatures/DiagnosticsTestUtilities/Diagnostics/AbstractDiagnosticProviderBasedUserDiagnosticTest.cs @@ -166,7 +166,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/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/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 f565458cb4cc7..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; @@ -452,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); @@ -610,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); } @@ -1048,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); @@ -1248,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/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..67da73f6228d3 100644 --- a/src/EditorFeatures/Test/SolutionCrawler/WorkCoordinatorTests.cs +++ b/src/EditorFeatures/Test/SolutionCrawler/WorkCoordinatorTests.cs @@ -1627,7 +1627,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; 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..d37bf7e205867 100644 --- a/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb +++ b/src/EditorFeatures/Test2/Diagnostics/DiagnosticProviderTests.vb @@ -352,7 +352,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/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..206e9e1bce3eb 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb @@ -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) @@ -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,8 @@ 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.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.BlockOnExpandedCompletion), True) state.SendInvokeCompletionList() Await state.WaitForUIRenderedAsync() @@ -6750,10 +6728,8 @@ 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.BlockOnExpandedCompletion), True) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) state.SendInvokeCompletionList() Await state.WaitForUIRenderedAsync() @@ -6790,10 +6766,8 @@ 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.BlockOnExpandedCompletion), True) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), False) ' trigger completion with import completion disabled state.SendInvokeCompletionList() @@ -6831,7 +6805,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 +6835,8 @@ 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.BlockOnExpandedCompletion), True) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) ' trigger completion with import completion enabled state.SendInvokeCompletionList() @@ -6886,7 +6858,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 +6867,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.BlockOnExpandedCompletion), 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 +7320,13 @@ 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.BlockOnExpandedCompletion), 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 +7389,13 @@ 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.BlockOnExpandedCompletion), 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 +7458,13 @@ 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.BlockOnExpandedCompletion), 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 +7527,13 @@ 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.BlockOnExpandedCompletion), 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 +7597,13 @@ 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.BlockOnExpandedCompletion), 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 +7636,13 @@ 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.BlockOnExpandedCompletion), 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 +7679,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 +7732,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 +7747,8 @@ 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.BlockOnExpandedCompletion), True) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), True) state.SendTypeChars("mytask") Await state.WaitForAsynchronousOperationsAsync() @@ -7851,9 +7791,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 +7822,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 +8257,10 @@ 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.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.BlockOnExpandedCompletion), True) + state.SendInvokeCompletionList() state.AssertItemsInOrder(New String() { "A", ' Method, properties, and imported extension methods alphabetical ordered @@ -8636,9 +8578,8 @@ 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) + state.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.BlockOnExpandedCompletion), True) Dim expectedText = $" using CC; @@ -8684,7 +8625,8 @@ 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.Workspace.GlobalOptions.SetGlobalOption(New OptionKey(CompletionOptionsStorage.BlockOnExpandedCompletion), True) state.SendInvokeCompletionList() Await state.WaitForAsynchronousOperationsAsync() @@ -8737,7 +8679,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 +8728,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 +8771,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 +8821,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 +8871,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 +9237,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 +9293,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"}) @@ -9503,6 +9453,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]> 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/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/Rename/InlineRenameTests.vb b/src/EditorFeatures/Test2/Rename/InlineRenameTests.vb index 2b3417902bae8..1b79834651e4a 100644 --- a/src/EditorFeatures/Test2/Rename/InlineRenameTests.vb +++ b/src/EditorFeatures/Test2/Rename/InlineRenameTests.vb @@ -11,7 +11,6 @@ Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces 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 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/AbstractCompletionProviderTests.cs b/src/EditorFeatures/TestUtilities/Completion/AbstractCompletionProviderTests.cs index eb645347926dc..c408f900de8f4 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)) @@ -1042,7 +1037,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 +1067,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 +1077,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 +1114,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/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/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 94a610785dc8e..b905addc182d9 100644 --- a/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs +++ b/src/EditorFeatures/TestUtilities/Formatting/CoreFormatterTestsBase.cs @@ -282,7 +282,8 @@ await AssertFormatAsync( protected static void AssertFormatOnArbitraryNode(SyntaxNode node, string expected) { using var workspace = new AdhocWorkspace(); - var options = SyntaxFormattingOptions.Default; + 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(); 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/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..d9bd483a37eda 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); @@ -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..c72361cbb9011 100644 --- a/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb +++ b/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb @@ -445,7 +445,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/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/VisualBasicTest/Classification/SemanticClassifierTests.vb b/src/EditorFeatures/VisualBasicTest/Classification/SemanticClassifierTests.vb index 073776aead0e6..201ea6b3f834d 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,90 @@ 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_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/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/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/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/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 e6612439fb373..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) 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/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/Features/CSharp/Portable/AddImport/CSharpAddImportFeatureService.cs b/src/Features/CSharp/Portable/AddImport/CSharpAddImportFeatureService.cs index 38968bc5ea9e8..d683b1726eb6e 100644 --- a/src/Features/CSharp/Portable/AddImport/CSharpAddImportFeatureService.cs +++ b/src/Features/CSharp/Portable/AddImport/CSharpAddImportFeatureService.cs @@ -13,7 +13,6 @@ 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; @@ -290,7 +289,7 @@ protected override string GetDescription(IReadOnlyList nameParts) protected override (string description, bool hasExistingImport) GetDescription( Document document, - CodeGenerationPreferences preferences, + AddImportPlacementOptions options, INamespaceOrTypeSymbol namespaceOrTypeSymbol, SemanticModel semanticModel, SyntaxNode contextNode, @@ -305,7 +304,7 @@ protected override (string description, bool hasExistingImport) GetDescription( namespaceOrTypeSymbol, semanticModel, contextNode); var (usingDirective, hasExistingUsing) = GetUsingDirective( - document, (CSharpCodeGenerationPreferences)preferences, namespaceOrTypeSymbol, semanticModel, root, contextNode); + document, options, namespaceOrTypeSymbol, semanticModel, root, contextNode); var externAliasString = externAlias != null ? $"extern alias {externAlias.Identifier.ValueText};" : null; var usingDirectiveString = usingDirective != null ? GetUsingDirectiveString(namespaceOrTypeSymbol) : null; @@ -342,26 +341,25 @@ 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 preferences = await CSharpCodeGenerationPreferences.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var (externAliasDirective, hasExistingExtern) = GetExternAliasDirective( namespaceOrTypeSymbol, semanticModel, contextNode); var (usingDirective, hasExistingUsing) = GetUsingDirective( - document, preferences, namespaceOrTypeSymbol, semanticModel, root, contextNode); + document, options, namespaceOrTypeSymbol, semanticModel, root, contextNode); using var _ = ArrayBuilder.GetInstance(out var newImports); @@ -383,16 +381,15 @@ private async Task AddImportWorkerAsync( var addImportService = document.GetLanguageService(); var generator = SyntaxGenerator.GetGenerator(document); var newRoot = addImportService.AddImports( - semanticModel.Compilation, root, contextNode, newImports, generator, preferences, 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 root = GetCompilationUnitSyntaxNode(contextNode, cancellationToken); - var preferences = await CSharpCodeGenerationPreferences.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); var usingDirective = SyntaxFactory.UsingDirective( CreateNameSyntax(namespaceParts, namespaceParts.Count - 1)); @@ -401,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, preferences, allowInHiddenRegions, cancellationToken); + compilation, root, contextNode, usingDirective, generator, options, cancellationToken); return document.WithSyntaxRoot(newRoot); } @@ -438,7 +435,7 @@ private static (ExternAliasDirectiveSyntax, bool hasExistingImport) GetExternAli private (UsingDirectiveSyntax, bool hasExistingImport) GetUsingDirective( Document document, - CSharpCodeGenerationPreferences preferences, + AddImportPlacementOptions options, INamespaceOrTypeSymbol namespaceOrTypeSymbol, SemanticModel semanticModel, CompilationUnitSyntax root, @@ -457,7 +454,7 @@ private static (ExternAliasDirectiveSyntax, bool hasExistingImport) GetExternAli // help create the final using. var dummyUsing = SyntaxFactory.UsingDirective(nameSyntax); - var container = addImportService.GetImportContainer(root, contextNode, dummyUsing, preferences); + var container = addImportService.GetImportContainer(root, contextNode, dummyUsing, options); var namespaceToAddTo = container as BaseNamespaceDeclarationSyntax; // Replace the alias that GenerateTypeSyntax added if we want this to be looked diff --git a/src/Features/CSharp/Portable/BraceCompletion/CurlyBraceCompletionService.cs b/src/Features/CSharp/Portable/BraceCompletion/CurlyBraceCompletionService.cs index 9386280a44803..b70e150999cac 100644 --- a/src/Features/CSharp/Portable/BraceCompletion/CurlyBraceCompletionService.cs +++ b/src/Features/CSharp/Portable/BraceCompletion/CurlyBraceCompletionService.cs @@ -116,7 +116,7 @@ public override Task AllowOverTypeAsync(BraceCompletionContext context, Ca var textToFormat = originalDocumentText; if (closingPointLine - openingPointLine == 1) { - var newLineString = options.FormattingOptions.GetOption(FormattingOptions2.NewLine); + var newLineString = options.FormattingOptions.NewLine; newLineEdit = new TextChange(new TextSpan(closingPoint - 1, 0), newLineString); textToFormat = originalDocumentText.WithChanges(newLineEdit.Value); @@ -330,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; @@ -351,14 +351,14 @@ public static AbstractFormattingRule ForIndentStyle(FormattingOptions.IndentStyl public override AbstractFormattingRule WithOptions(SyntaxFormattingOptions options) { - var cachedOptions = new CachedOptions(options.Options); + var newOptions = options as CSharpSyntaxFormattingOptions ?? CSharpSyntaxFormattingOptions.Default; - if (cachedOptions == _options) + if (_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInObjectCollectionArrayInitializers) == newOptions.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInObjectCollectionArrayInitializers)) { 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) @@ -377,7 +377,7 @@ public override AbstractFormattingRule WithOptions(SyntaxFormattingOptions optio SyntaxKind.ArrayInitializerExpression, SyntaxKind.ImplicitArrayCreationExpression)) { - if (_options.NewLinesForBracesInObjectCollectionArrayInitializers) + if (_options.NewLines.HasFlag(NewLinePlacement.BeforeOpenBraceInObjectCollectionArrayInitializers)) { return CreateAdjustNewLinesOperation(1, AdjustNewLinesOption.PreserveLines); } @@ -419,45 +419,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/Suppression/CSharpSuppressionCodeFixProvider.cs b/src/Features/CSharp/Portable/CodeFixes/Suppression/CSharpSuppressionCodeFixProvider.cs index 60a557cfeb8c3..bb6c888c8024b 100644 --- a/src/Features/CSharp/Portable/CodeFixes/Suppression/CSharpSuppressionCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/CodeFixes/Suppression/CSharpSuppressionCodeFixProvider.cs @@ -10,7 +10,7 @@ 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; 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/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..f51bae194c60f 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/ExtensionMethodImportCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/ExtensionMethodImportCompletionProvider.cs @@ -5,17 +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; namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers @@ -46,9 +41,6 @@ protected override ImmutableArray GetImportedNamespaces( CancellationToken cancellationToken) => ImportCompletionProviderHelper.GetImportedNamespaces(location, semanticModel); - protected override Task CreateContextAsync(Document document, int position, CancellationToken cancellationToken) - => ImportCompletionProviderHelper.CreateContextAsync(document, position, cancellationToken); - protected override bool IsFinalSemicolonOfUsingOrExtern(SyntaxNode directive, SyntaxToken token) { if (token.IsKind(SyntaxKind.None) || token.IsMissing) diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/ImportCompletionProviderHelper.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/ImportCompletionProviderHelper.cs index 369f67c642348..31e8e19dafc55 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/ImportCompletionProviderHelper.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/ImportCompletionProviderHelper.cs @@ -3,12 +3,8 @@ // 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.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers @@ -20,14 +16,5 @@ public static ImmutableArray GetImportedNamespaces( SemanticModel semanticModel) => semanticModel.GetUsingNamespacesInScope(location) .SelectAsArray(namespaceSymbol => namespaceSymbol.ToDisplayString(SymbolDisplayFormats.NameFormat)); - - public 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); - Contract.ThrowIfNull(semanticModel); - return CSharpSyntaxContext.CreateContext(document, semanticModel, position, cancellationToken); - } } } diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/TypeImportCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/ImportCompletion/TypeImportCompletionProvider.cs index e25e9152f33cd..1b8e810b27627 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,8 @@ 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 { @@ -47,9 +43,6 @@ protected override ImmutableArray GetImportedNamespaces( CancellationToken cancellationToken) => ImportCompletionProviderHelper.GetImportedNamespaces(location, semanticModel); - protected override Task CreateContextAsync(Document document, int position, CancellationToken cancellationToken) - => ImportCompletionProviderHelper.CreateContextAsync(document, position, cancellationToken); - protected override bool IsFinalSemicolonOfUsingOrExtern(SyntaxNode directive, SyntaxToken token) { if (token.IsKind(SyntaxKind.None) || token.IsMissing) 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/ConvertAutoPropertyToFullProperty/CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ConvertAutoPropertyToFullProperty/CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs index 4390eb9b11771..c837c80b34065 100644 --- a/src/Features/CSharp/Portable/ConvertAutoPropertyToFullProperty/CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ConvertAutoPropertyToFullProperty/CSharpConvertAutoPropertyToFullPropertyCodeRefactoringProvider.cs @@ -81,7 +81,7 @@ private static SyntaxNode GetUpdatedAccessor(CSharpCodeGenerationPreferences pre var newAccessor = AddStatement(accessor, statement); var accessorDeclarationSyntax = (AccessorDeclarationSyntax)newAccessor; - var preference = GetAccessorExpressionBodyPreference(preferences); + var preference = preferences.PreferExpressionBodiedAccessors; if (preference == ExpressionBodyPreference.Never) { return accessorDeclarationSyntax.WithSemicolonToken(default); @@ -117,7 +117,7 @@ internal override SyntaxNode ConvertPropertyToExpressionBodyIfDesired( { var propertyDeclaration = (PropertyDeclarationSyntax)property; - var preference = GetPropertyExpressionBodyPreference(preferences); + 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(CSharpCodeGenerationPreferences preferences) - => preferences.Options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors).Value; - - internal static ExpressionBodyPreference GetPropertyExpressionBodyPreference(CSharpCodeGenerationPreferences preferences) - => preferences.Options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties).Value; - internal override SyntaxNode GetTypeBlock(SyntaxNode syntaxNode) => syntaxNode; 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/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/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/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/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/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/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/xlf/CSharpFeaturesResources.cs.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.cs.xlf index 0973c83d3f393..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 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.de.xlf index 1f32da3391bfe..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 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.es.xlf index 4511fe240f950..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 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.fr.xlf index 83c192c454017..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 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.it.xlf index 059515829ba39..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 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ja.xlf index a730dfa534ff3..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 正規文字列に変換する diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ko.xlf index 4091a3a7311f6..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 일반 문자열로 변환 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pl.xlf index 958bc8e9e885c..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 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.pt-BR.xlf index 7de4bca5edbea..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 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.ru.xlf index b00ad6f2adc8b..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 Преобразовать в обычную строку diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.tr.xlf index ac56005f5a0e8..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 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hans.xlf index 5c8d1d8e66197..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 转换为正则字符串 diff --git a/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf b/src/Features/CSharp/Portable/xlf/CSharpFeaturesResources.zh-Hant.xlf index c563694b3a485..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 轉換為一般字串 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..65125d8197c34 100644 --- a/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixProvider.cs @@ -8,6 +8,8 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Packaging; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SymbolSearch; @@ -57,12 +59,17 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var addImportService = document.GetLanguageService(); var solution = document.Project.Solution; - var options = solution.Options; - var searchReferenceAssemblies = options.GetOption(SymbolSearchOptions.SuggestForTypesInReferenceAssemblies, document.Project.Language); - var searchNuGetPackages = options.GetOption(SymbolSearchOptions.SuggestForTypesInNuGetPackages, document.Project.Language); + var searchNuGetPackages = solution.Options.GetOption(SymbolSearchOptions.SuggestForTypesInNuGetPackages, document.Project.Language); - var symbolSearchService = searchReferenceAssemblies || searchNuGetPackages + var placement = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + + var options = new AddImportOptions( + context.Options.SearchReferenceAssemblies, + context.Options.HideAdvancedMembers, + placement); + + var symbolSearchService = options.SearchReferenceAssemblies || searchNuGetPackages ? _symbolSearchService ?? solution.Workspace.Services.GetService() : null; @@ -72,7 +79,7 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) : ImmutableArray.Empty; var fixesForDiagnostic = await addImportService.GetFixesForDiagnosticsAsync( - document, span, diagnostics, MaxResults, symbolSearchService, searchReferenceAssemblies, packageSources, cancellationToken).ConfigureAwait(false); + document, span, diagnostics, MaxResults, symbolSearchService, options, packageSources, cancellationToken).ConfigureAwait(false); foreach (var (diagnostic, fixes) in fixesForDiagnostic) { diff --git a/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs b/src/Features/Core/Portable/AddImport/AbstractAddImportFeatureService.cs index 40c95f26c90cf..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; @@ -46,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, CodeGenerationPreferences preferences, 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); @@ -66,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); @@ -75,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); @@ -98,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); } } @@ -123,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. @@ -133,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); @@ -489,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)); @@ -518,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); @@ -527,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); @@ -536,7 +526,7 @@ public async Task> GetUniqueFixesAsync( return await GetUniqueFixesAsyncInCurrentProcessAsync( document, span, diagnosticIds, - symbolSearchService, searchReferenceAssemblies, + symbolSearchService, options, packageSources, cancellationToken).ConfigureAwait(false); } @@ -545,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. @@ -562,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..c69550cb064f9 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)] bool SearchReferenceAssemblies, + [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 230b680865f12..1671105787b8a 100644 --- a/src/Features/Core/Portable/AddImport/References/MetadataSymbolReference.cs +++ b/src/Features/Core/Portable/AddImport/References/MetadataSymbolReference.cs @@ -10,7 +10,6 @@ using System.Threading; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeGeneration; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Tags; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -42,10 +41,10 @@ public MetadataSymbolReference( protected override bool ShouldAddWithExistingImport(Document document) => true; protected override (string description, bool hasExistingImport) GetDescription( - Document document, CodeGenerationPreferences preferences, SyntaxNode node, + Document document, AddImportPlacementOptions options, SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken) { - var (description, hasExistingImport) = base.GetDescription(document, preferences, node, semanticModel, cancellationToken); + var (description, hasExistingImport) = base.GetDescription(document, options, node, semanticModel, cancellationToken); if (description == null) { return (null, false); 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 12939dbe3e1f5..3f85b7457f2f8 100644 --- a/src/Features/Core/Portable/AddImport/References/ProjectSymbolReference.cs +++ b/src/Features/Core/Portable/AddImport/References/ProjectSymbolReference.cs @@ -87,10 +87,10 @@ protected override AddImportFixData GetFixData( } protected override (string description, bool hasExistingImport) GetDescription( - Document document, CodeGenerationPreferences preferences, SyntaxNode node, + Document document, AddImportPlacementOptions options, SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken) { - var (description, hasExistingImport) = base.GetDescription(document, preferences, node, semanticModel, cancellationToken); + var (description, hasExistingImport) = base.GetDescription(document, options, node, semanticModel, cancellationToken); if (description == null) { return (null, false); 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 ed39d369ee50f..45f8cf54a43f6 100644 --- a/src/Features/Core/Portable/AddImport/References/SymbolReference.cs +++ b/src/Features/Core/Portable/AddImport/References/SymbolReference.cs @@ -10,8 +10,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeGeneration; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Tags; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -54,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. @@ -68,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); @@ -81,11 +79,10 @@ private async Task> GetTextChangesAsync( public sealed override async Task TryGetFixDataAsync( Document document, SyntaxNode node, - bool allowInHiddenRegions, CancellationToken cancellationToken) + AddImportPlacementOptions options, CancellationToken cancellationToken) { - var preferences = await CodeGenerationPreferences.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var (description, hasExistingImport) = GetDescription(document, preferences, node, semanticModel, cancellationToken); + var (description, hasExistingImport) = GetDescription(document, options, node, semanticModel, cancellationToken); if (description == null) { return null; @@ -116,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, @@ -130,11 +127,11 @@ protected abstract AddImportFixData GetFixData( protected abstract CodeActionPriority GetPriority(Document document); protected virtual (string description, bool hasExistingImport) GetDescription( - Document document, CodeGenerationPreferences preferences, SyntaxNode node, + Document document, AddImportPlacementOptions options, SyntaxNode node, SemanticModel semanticModel, CancellationToken cancellationToken) { return provider.GetDescription( - document, preferences, SymbolResult.Symbol, semanticModel, node, cancellationToken); + document, options, SymbolResult.Symbol, semanticModel, node, cancellationToken); } } } 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..d85f70bf82b99 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,10 +60,10 @@ public SymbolReferenceFinder( _node = node; _symbolSearchService = symbolSearchService; - _searchReferenceAssemblies = searchReferenceAssemblies; + _options = options; _packageSources = packageSources; - if (_searchReferenceAssemblies || packageSources.Length > 0) + if (options.SearchReferenceAssemblies || packageSources.Length > 0) { Contract.ThrowIfNull(symbolSearchService); } @@ -217,14 +219,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..cc556990f14e1 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.SearchReferenceAssemblies) { cancellationToken.ThrowIfCancellationRequested(); await FindReferenceAssemblyTypeReferencesAsync( diff --git a/src/Features/Core/Portable/AliasAmbiguousType/AbstractAliasAmbiguousTypeCodeFixProvider.cs b/src/Features/Core/Portable/AliasAmbiguousType/AbstractAliasAmbiguousTypeCodeFixProvider.cs index c137b7e50340d..ece6c991a3617 100644 --- a/src/Features/Core/Portable/AliasAmbiguousType/AbstractAliasAmbiguousTypeCodeFixProvider.cs +++ b/src/Features/Core/Portable/AliasAmbiguousType/AbstractAliasAmbiguousTypeCodeFixProvider.cs @@ -7,7 +7,7 @@ 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; @@ -46,9 +46,8 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) var syntaxGenerator = document.GetRequiredLanguageService(); var codeGenerator = document.GetRequiredLanguageService(); var compilation = semanticModel.Compilation; - var preferences = await CodeGenerationPreferences.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); + var options = await AddImportPlacementOptions.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); - var allowInHiddenRegions = document.CanAddImportsInHiddenRegions(); var codeActionsBuilder = ImmutableArray.CreateBuilder(symbolInfo.CandidateSymbols.Length); foreach (var symbol in symbolInfo.CandidateSymbols.Cast()) { @@ -57,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, preferences, 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/ChangeSignature/AbstractChangeSignatureService.cs b/src/Features/Core/Portable/ChangeSignature/AbstractChangeSignatureService.cs index f79d2c37b6f84..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; @@ -415,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/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 64e706190a356..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,7 @@ using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Shared.Extensions; diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageFixAllCodeAction.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageFixAllCodeAction.cs index 9cb4dbad654bd..407042a49b2dd 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageFixAllCodeAction.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.GlobalSuppressMessageFixAllCodeAction.cs @@ -11,7 +11,7 @@ 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; diff --git a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs index 63d8a83d48eec..0d7875d5989b8 100644 --- a/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs +++ b/src/Features/Core/Portable/CodeFixes/Suppression/AbstractSuppressionCodeFixProvider.cs @@ -10,7 +10,7 @@ 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; @@ -200,7 +200,7 @@ private async Task> GetSuppressionsAsync( skipSuppressMessage = suppressMessageAttribute == null || !suppressMessageAttribute.IsAttribute(); } - var lazyFormattingOptions = (SyntaxFormattingOptions?)null; + var lazyFormattingOptions = (SyntaxFormattingOptions)null; var result = ArrayBuilder.GetInstance(); foreach (var diagnostic in diagnostics) { @@ -211,7 +211,7 @@ private async Task> GetSuppressionsAsync( { // pragma warning disable. lazyFormattingOptions ??= await SyntaxFormattingOptions.FromDocumentAsync(documentOpt, cancellationToken).ConfigureAwait(false); - nestedActions.Add(PragmaWarningCodeAction.Create(suppressionTargetInfo, documentOpt, lazyFormattingOptions.Value, diagnostic, this)); + nestedActions.Add(PragmaWarningCodeAction.Create(suppressionTargetInfo, documentOpt, lazyFormattingOptions, diagnostic, this)); } // SuppressMessageAttribute suppression is not supported for compiler diagnostics. diff --git a/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsFeatureService.cs b/src/Features/Core/Portable/CodeRefactorings/AddMissingImports/AbstractAddMissingImportsFeatureService.cs index eaa49c241a508..e8bb5bf5b3a2f 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( + SearchReferenceAssemblies: true, + 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)); 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/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/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 92c99eb637d8c..925e0c51308fc 100644 --- a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs @@ -11,7 +11,7 @@ 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; @@ -607,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); @@ -652,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. @@ -732,10 +732,10 @@ await FixReferencesAsync(document, changeNamespaceService, addImportService, ref } } - var preferences = await CodeGenerationPreferences.FromDocumentAsync(document, 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, preferences); + var container = addImportService.GetImportContainer(root, refNode, dummyImport, addImportsOptions); containers.Add(container); } @@ -813,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 @@ -823,7 +823,6 @@ private static async Task AddImportsInContainersAsync( containers = containers.Sort(SyntaxNodeSpanStartComparer.Instance); } - var preferences = await CodeGenerationPreferences.FromDocumentAsync(document, cancellationToken).ConfigureAwait(false); var generator = document.GetRequiredLanguageService(); var imports = CreateImports(document, names, withFormatterAnnotation: true); @@ -838,7 +837,7 @@ private static async Task AddImportsInContainersAsync( var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - root = addImportService.AddImports(compilation, root, contextLocation, imports, generator, preferences, allowInHiddenRegions, cancellationToken); + root = addImportService.AddImports(compilation, root, contextLocation, imports, generator, options, cancellationToken); document = document.WithSyntaxRoot(root); } 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/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..4e9a12a8da99f 100644 --- a/src/Features/Core/Portable/Completion/CompletionOptions.cs +++ b/src/Features/Core/Portable/Completion/CompletionOptions.cs @@ -2,201 +2,37 @@ // The .NET Foundation 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 BlockOnExpandedCompletion = 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 - { - [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")); - } } } diff --git a/src/Features/Core/Portable/Completion/CompletionOptionsStorage.cs b/src/Features/Core/Portable/Completion/CompletionOptionsStorage.cs new file mode 100644 index 0000000000000..f192fe5210c19 --- /dev/null +++ b/src/Features/Core/Portable/Completion/CompletionOptionsStorage.cs @@ -0,0 +1,106 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using 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), + BlockOnExpandedCompletion: options.GetOption(BlockOnExpandedCompletion)); + + // 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); + + // Test-only option + // Set this to true to have a deterministic behavior for expand items. Otherwise, expand items might not + // be included in the completion list if the calculation is slow. + public static readonly Option2 BlockOnExpandedCompletion + = new(nameof(CompletionOptions), nameof(BlockOnExpandedCompletion), 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/Features/Core/Portable/Completion/ExpandedCompletionMode.cs b/src/Features/Core/Portable/Completion/ExpandedCompletionMode.cs new file mode 100644 index 0000000000000..56a7abbd701a0 --- /dev/null +++ b/src/Features/Core/Portable/Completion/ExpandedCompletionMode.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.Completion +{ + internal enum ExpandedCompletionMode + { + 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/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 1e29f23f3cb0c..07c7881120714 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.CodeGeneration; using Microsoft.CodeAnalysis.Completion.Log; using Microsoft.CodeAnalysis.Editing; @@ -22,10 +22,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 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(); @@ -40,44 +39,42 @@ public Task NotifyCommittingItemAsync(Document document, CompletionItem item, ch public override async Task ProvideCompletionsAsync(CompletionContext completionContext) { + // Don't trigger import completion if the option value is "default" and the experiment is disabled for the user. + var importCompletionOptionValue = completionContext.CompletionOptions.ShowItemsFromUnimportedNamespaces; + if (importCompletionOptionValue == false || + (importCompletionOptionValue == null && !completionContext.CompletionOptions.TypeImportCompletion)) + { + 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); + 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) { var semanticModel = syntaxContext.SemanticModel; - // The location is the containing node of the LeftToken, or the compilation unit itsef if LeftToken + // 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 = syntaxContext.LeftToken.Parent ?? syntaxContext.SyntaxTree.GetRoot(cancellationToken); var importedNamespaces = GetImportedNamespaces(location, semanticModel, cancellationToken); @@ -128,12 +125,11 @@ public override async Task GetChangeAsync( // Add required using/imports directive. var addImportService = document.GetRequiredLanguageService(); var generator = document.GetRequiredLanguageService(); - var preferences = await CodeGenerationPreferences.FromDocumentAsync(document, 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, preferences, 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/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..5dd4d72e6bd03 100644 --- a/src/Features/Core/Portable/Diagnostics/AnalyzerHelper.cs +++ b/src/Features/Core/Portable/Diagnostics/AnalyzerHelper.cs @@ -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, 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_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/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/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/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..a37a40209f8f6 100644 --- a/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs +++ b/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs @@ -2266,7 +2266,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 +2289,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 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/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..720e82edaf7ae --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/AbstractLanguageDetector.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.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; + + var syntaxFacts = Info.SyntaxFacts; + if (syntaxFacts.IsStringLiteral(token)) + return IsEmbeddedLanguageStringLiteralToken(token, semanticModel, cancellationToken, out options); + + if (token.RawKind == syntaxFacts.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 + { + 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 IsArgumentToParameterWithMatchingStringSyntaxAttribute(SemanticModel semanticModel, SyntaxNode argumentNode, CancellationToken cancellationToken, out TOptions options) + { + var operation = semanticModel.GetOperation(argumentNode, cancellationToken); + if (operation is IArgumentOperation { Parameter: { } parameter } && + HasMatchingStringSyntaxAttribute(parameter)) + { + options = GetOptionsFromSiblingArgument(argumentNode, 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(ISymbol symbol) + { + 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; + } + + 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 argumentNode, + SemanticModel semanticModel, + CancellationToken cancellationToken) + { + var syntaxFacts = Info.SyntaxFacts; + var argumentList = argumentNode.GetRequiredParent(); + var arguments = syntaxFacts.GetArgumentsOfArgumentList(argumentList); + foreach (var siblingArg in arguments) + { + if (siblingArg != argumentNode) + { + var expr = syntaxFacts.GetExpressionOfArgument(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..dc9992b0b7d6a --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/AbstractJsonDetectionAnalyzer.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.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 (token.RawKind == _info.StringLiteralTokenKind && + detector.TryParseString(token, context.SemanticModel, cancellationToken) == null && + IsProbablyJson(token)) + { + 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; + + context.ReportDiagnostic(DiagnosticHelper.Create( + this.Descriptor, + token.GetLocation(), + ReportDiagnostic.Info, + additionalLocations: null, + properties)); + } + } + } + } + + public bool IsProbablyJson(SyntaxToken token) + { + var chars = _info.VirtualCharService.TryConvertToVirtualChars(token); + var 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; + } + } +} 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..fbc331bdca346 --- /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.SyntaxFacts.SyntaxKinds.StringLiteralToken == 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_JSON_editor_features, createChangedDocument, nameof(FeaturesResources.Enable_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..1e6bcfc7e814e --- /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 (token.RawKind == _info.StringLiteralTokenKind) + { + var tree = detector.TryParseString(token, context.SemanticModel, 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..b26642ba732cc --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonEmbeddedClassifier.cs @@ -0,0 +1,191 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .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 = ImmutableArray.Create(info.StringLiteralTokenKind); + } + + public override void AddClassifications( + SyntaxToken token, + SemanticModel semanticModel, + ClassificationOptions options, + ArrayBuilder result, + CancellationToken cancellationToken) + { + if (_info.StringLiteralTokenKind != token.RawKind) + return; + + if (!options.ColorizeJsonPatterns) + return; + + var detector = JsonLanguageDetector.GetOrCreate(semanticModel.Compilation, _info); + var tree = detector.TryParseString(token, semanticModel, 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..c06616a45c538 --- /dev/null +++ b/src/Features/Core/Portable/EmbeddedLanguages/Json/LanguageServices/JsonLanguageDetector.cs @@ -0,0 +1,172 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Linq; +using System.Runtime.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); + + 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 (objectInitializer != null) + { + var initializers = syntaxFacts.GetMemberInitializersOfInitializer(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 83% rename from src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/AbstractRegexDiagnosticAnalyzer.cs rename to src/Features/Core/Portable/EmbeddedLanguages/RegularExpressions/LanguageServices/AbstractRegexDiagnosticAnalyzer.cs index aaef642242d26..4d12e1ce4f3d5 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. @@ -27,7 +25,7 @@ protected AbstractRegexDiagnosticAnalyzer(EmbeddedLanguageInfo info) : base(DiagnosticId, EnforceOnBuildValues.Regex, RegularExpressionsOptions.ReportInvalidRegexPatterns, - new LocalizableResourceString(nameof(FeaturesResources.Regex_issue_0), FeaturesResources.ResourceManager, typeof(FeaturesResources)), + new LocalizableResourceString(nameof(FeaturesResources.Invalid_regex_pattern), FeaturesResources.ResourceManager, typeof(FeaturesResources)), new LocalizableResourceString(nameof(FeaturesResources.Regex_issue_0), FeaturesResources.ResourceManager, typeof(FeaturesResources))) { _info = info; @@ -47,15 +45,9 @@ public void Analyze(SemanticModelAnalysisContext context) var option = context.GetOption(RegularExpressionsOptions.ReportInvalidRegexPatterns, syntaxTree.Options.Language); 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) { - 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*)(? public abstract class QuickInfoService : ILanguageService { + // Prevent inheritance outside of Roslyn. + internal QuickInfoService() + { + } + /// /// Gets the appropriate for the specified document. /// @@ -24,10 +31,20 @@ public abstract class QuickInfoService : ILanguageService /// /// Gets the associated with position in the document. /// - public virtual Task GetQuickInfoAsync( + public Task GetQuickInfoAsync( Document document, int position, CancellationToken cancellationToken = default) + { + Debug.Fail("For backwards API compat only, should not be called"); + return GetQuickInfoAsync(document, position, SymbolDescriptionOptions.Default, cancellationToken); + } + + internal virtual Task GetQuickInfoAsync( + Document document, + int position, + SymbolDescriptionOptions options, + CancellationToken cancellationToken) { return SpecializedTasks.Null(); } diff --git a/src/Features/Core/Portable/QuickInfo/QuickInfoServiceWithProviders.cs b/src/Features/Core/Portable/QuickInfo/QuickInfoServiceWithProviders.cs index f0f705d3e0766..8e28097574134 100644 --- a/src/Features/Core/Portable/QuickInfo/QuickInfoServiceWithProviders.cs +++ b/src/Features/Core/Portable/QuickInfo/QuickInfoServiceWithProviders.cs @@ -46,10 +46,9 @@ private ImmutableArray GetProviders() return _providers; } - public override async Task GetQuickInfoAsync(Document document, int position, CancellationToken cancellationToken) + internal override async Task GetQuickInfoAsync(Document document, int position, SymbolDescriptionOptions options, CancellationToken cancellationToken) { var extensionManager = _services.WorkspaceServices.GetRequiredService(); - var options = SymbolDescriptionOptions.From(document.Project); // returns the first non-empty quick info found (based on provider order) foreach (var provider in GetProviders()) diff --git a/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.cs b/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.cs index 67fccd78477b6..36332ab84bad3 100644 --- a/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.cs +++ b/src/Features/Core/Portable/SignatureHelp/AbstractSignatureHelpProvider.cs @@ -33,19 +33,9 @@ protected AbstractSignatureHelpProvider() public abstract bool IsTriggerCharacter(char ch); public abstract bool IsRetriggerCharacter(char ch); - public abstract SignatureHelpState? GetCurrentArgumentState(SyntaxNode root, int position, ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken); protected abstract Task GetItemsWorkerAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, SignatureHelpOptions options, CancellationToken cancellationToken); - /// - /// This overload is required for compatibility with existing extensions. - /// - protected static SignatureHelpItems? CreateSignatureHelpItems( - IList items, TextSpan applicableSpan, SignatureHelpState state) - { - return CreateSignatureHelpItems(items, applicableSpan, state, selectedItem: null); - } - protected static SignatureHelpItems? CreateSignatureHelpItems( IList? items, TextSpan applicableSpan, SignatureHelpState? state, int? selectedItem) { @@ -105,6 +95,7 @@ private static (IList items, int? selectedItem) Filter(IList< // adjust the selected item var selection = items[selectedItem.Value]; selectedItem = filteredList.IndexOf(selection); + return (filteredList, selectedItem); } @@ -114,12 +105,6 @@ private static bool Include(SignatureHelpItem item, IEnumerable paramete return parameterNames.All(itemParameterNames.Contains); } - public async Task GetCurrentArgumentStateAsync(Document document, int position, TextSpan currentSpan, CancellationToken cancellationToken) - { - var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - return GetCurrentArgumentState(root, position, document.GetRequiredLanguageService(), currentSpan, cancellationToken); - } - // TODO: remove once Pythia moves to ExternalAccess APIs [Obsolete("Use overload without ISymbolDisplayService")] #pragma warning disable CA1822 // Mark members as static - see obsolete comment above. diff --git a/src/Features/Core/Portable/SignatureHelp/SignatureHelpOptions.cs b/src/Features/Core/Portable/SignatureHelp/SignatureHelpOptions.cs index 794cdad803615..8b2d39eb8e91b 100644 --- a/src/Features/Core/Portable/SignatureHelp/SignatureHelpOptions.cs +++ b/src/Features/Core/Portable/SignatureHelp/SignatureHelpOptions.cs @@ -3,18 +3,12 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.Completion; -using Microsoft.CodeAnalysis.Options; namespace Microsoft.CodeAnalysis.SignatureHelp { internal readonly record struct SignatureHelpOptions( bool HideAdvancedMembers) { - public static SignatureHelpOptions From(Project project) - => From(project.Solution.Options, project.Language); - - public static SignatureHelpOptions From(OptionSet options, string language) - => new( - HideAdvancedMembers: options.GetOption(CompletionOptions.Metadata.HideAdvancedMembers, language)); + public static readonly SignatureHelpOptions Default = new(CompletionOptions.Default.HideAdvancedMembers); } } diff --git a/src/Features/Core/Portable/SignatureHelp/SignatureHelpOptionsStorage.cs b/src/Features/Core/Portable/SignatureHelp/SignatureHelpOptionsStorage.cs new file mode 100644 index 0000000000000..aa5bd62a80307 --- /dev/null +++ b/src/Features/Core/Portable/SignatureHelp/SignatureHelpOptionsStorage.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.Completion; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.SignatureHelp +{ + // TODO: Move to EditorFeatures https://github.com/dotnet/roslyn/issues/59184 + internal static class SignatureHelpOptionsStorage + { + public static SignatureHelpOptions GetSignatureHelpOptions(this IGlobalOptionService globalOptions, string language) + => new( + HideAdvancedMembers: globalOptions.GetOption(CompletionOptionsStorage.HideAdvancedMembers, language)); + } +} diff --git a/src/Features/Core/Portable/Snippets/SnippetFunctionService.cs b/src/Features/Core/Portable/Snippets/SnippetFunctionService.cs new file mode 100644 index 0000000000000..4aa7f180eb464 --- /dev/null +++ b/src/Features/Core/Portable/Snippets/SnippetFunctionService.cs @@ -0,0 +1,159 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis; +internal abstract class SnippetFunctionService : ILanguageService +{ + /// + /// Language specific format for switch cases. + /// + public abstract string SwitchCaseFormat { get; } + + /// + /// Language specific format for default switch case. + /// + public abstract string SwitchDefaultCaseForm { get; } + + /// + /// Gets the name of the class that contains the specified position. + /// + public abstract Task GetContainingClassNameAsync(Document document, int position, CancellationToken cancellationToken); + + /// + /// For a specified snippet field, replace it with the fully qualified name then simplify in the context of the document + /// in order to retrieve the simplified type name. + /// + public static async Task GetSimplifiedTypeNameAsync(Document document, TextSpan fieldSpan, string fullyQualifiedTypeName, CancellationToken cancellationToken) + { + // Insert the function parameter (fully qualified type name) into the document. + var updatedTextSpan = new TextSpan(fieldSpan.Start, fullyQualifiedTypeName.Length); + + var textChange = new TextChange(fieldSpan, fullyQualifiedTypeName); + var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + var documentWithFullyQualifiedTypeName = document.WithText(text.WithChanges(textChange)); + + // Simplify + var simplifiedTypeName = await GetSimplifiedTypeNameAtSpanAsync(documentWithFullyQualifiedTypeName, updatedTextSpan, cancellationToken).ConfigureAwait(false); + return simplifiedTypeName; + } + + /// + /// For a document with the default switch snippet inserted, generate the expanded set of cases based on the value + /// of the field currently inserted into the switch statement. + /// + public async Task GetSwitchExpansionAsync(Document document, TextSpan caseGenerationLocation, TextSpan switchExpressionLocation, CancellationToken cancellationToken) + { + var typeSymbol = await GetEnumSymbolAsync(document, switchExpressionLocation, cancellationToken).ConfigureAwait(false); + if (typeSymbol?.TypeKind != TypeKind.Enum) + { + return null; + } + + var enumFields = typeSymbol.GetMembers().Where(m => m.Kind == SymbolKind.Field && m.IsStatic); + if (!enumFields.Any()) + { + return null; + } + + // Find and use the most simplified legal version of the enum type name in this context + var fullyQualifiedEnumName = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + var simplifiedTypeName = await GetSimplifiedEnumNameAsync(document, fullyQualifiedEnumName, enumFields.First().Name, caseGenerationLocation, cancellationToken).ConfigureAwait(false); + if (simplifiedTypeName == null) + { + return null; + } + + using var _ = PooledStringBuilder.GetInstance(out var casesBuilder); + foreach (var member in enumFields) + { + casesBuilder.AppendFormat(SwitchCaseFormat, simplifiedTypeName, member.Name); + } + + casesBuilder.Append(SwitchDefaultCaseForm); + return casesBuilder.ToString(); + } + + /// + /// Parse the XML snippet function attribute to determine the function name and parameter. + /// + public static bool TryGetSnippetFunctionInfo( + string? xmlFunctionText, + [NotNullWhen(true)] out string? snippetFunctionName, + [NotNullWhen(true)] out string? param) + { + if (string.IsNullOrEmpty(xmlFunctionText)) + { + snippetFunctionName = null; + param = null; + return false; + } + + if (!xmlFunctionText.Contains('(') || + !xmlFunctionText.Contains(')') || + xmlFunctionText.IndexOf(')') < xmlFunctionText.IndexOf('(')) + { + snippetFunctionName = null; + param = null; + return false; + } + + snippetFunctionName = xmlFunctionText.Substring(0, xmlFunctionText.IndexOf('(')); + + var paramStart = xmlFunctionText.IndexOf('(') + 1; + var paramLength = xmlFunctionText.LastIndexOf(')') - xmlFunctionText.IndexOf('(') - 1; + param = xmlFunctionText.Substring(paramStart, paramLength); + return true; + } + + protected abstract Task GetEnumSymbolAsync(Document document, TextSpan switchExpressionSpan, CancellationToken cancellationToken); + + protected abstract Task<(Document, TextSpan)> GetDocumentWithEnumCaseAsync(Document document, string fullyQualifiedTypeName, string firstEnumMemberName, TextSpan caseGenerationLocation, CancellationToken cancellationToken); + + private async Task GetSimplifiedEnumNameAsync( + Document document, + string fullyQualifiedTypeName, + string firstEnumMemberName, + TextSpan caseGenerationLocation, + CancellationToken cancellationToken) + { + // Insert switch with enum case into the document. + var (documentWithFullyQualified, fullyQualifiedTypeLocation) = await GetDocumentWithEnumCaseAsync(document, fullyQualifiedTypeName, firstEnumMemberName, caseGenerationLocation, cancellationToken).ConfigureAwait(false); + + // Simplify enum case. + var simplifiedEnum = await GetSimplifiedTypeNameAtSpanAsync(documentWithFullyQualified, fullyQualifiedTypeLocation, cancellationToken).ConfigureAwait(false); + return simplifiedEnum; + } + + private static async Task GetSimplifiedTypeNameAtSpanAsync(Document documentWithFullyQualifiedTypeName, TextSpan fullyQualifiedTypeSpan, CancellationToken cancellationToken) + { + // Simplify + var typeAnnotation = new SyntaxAnnotation(); + var syntaxRoot = await documentWithFullyQualifiedTypeName.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var nodeToReplace = syntaxRoot.DescendantNodes().FirstOrDefault(n => n.Span == fullyQualifiedTypeSpan); + + if (nodeToReplace == null) + { + return null; + } + + var updatedRoot = syntaxRoot.ReplaceNode(nodeToReplace, nodeToReplace.WithAdditionalAnnotations(typeAnnotation, Simplifier.Annotation)); + var documentWithAnnotations = documentWithFullyQualifiedTypeName.WithSyntaxRoot(updatedRoot); + + var simplifiedDocument = await Simplifier.ReduceAsync(documentWithAnnotations, cancellationToken: cancellationToken).ConfigureAwait(false); + var simplifiedRoot = await simplifiedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var simplifiedTypeName = simplifiedRoot.GetAnnotatedNodesAndTokens(typeAnnotation).Single().ToString(); + return simplifiedTypeName; + } +} diff --git a/src/Features/Core/Portable/Snippets/SnippetUtilities.cs b/src/Features/Core/Portable/Snippets/SnippetUtilities.cs new file mode 100644 index 0000000000000..d868e29267f93 --- /dev/null +++ b/src/Features/Core/Portable/Snippets/SnippetUtilities.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 Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.LanguageServices; +using System.Diagnostics.CodeAnalysis; + +namespace Microsoft.CodeAnalysis; +internal class SnippetUtilities +{ + public static bool TryGetWordOnLeft(int position, SourceText currentText, ISyntaxFactsService syntaxFactsService, [NotNullWhen(true)] out TextSpan? wordSpan) + { + var endPosition = position; + var startPosition = endPosition; + + // Find the snippet shortcut + while (startPosition > 0) + { + var c = currentText[startPosition - 1]; + if (!syntaxFactsService.IsIdentifierPartCharacter(c) && c != '#' && c != '~') + { + break; + } + + startPosition--; + } + + if (startPosition == endPosition) + { + wordSpan = null; + return false; + } + + wordSpan = TextSpan.FromBounds(startPosition, endPosition); + return true; + } +} diff --git a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.cs b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.cs index c3ee256080e42..ae704259925d1 100644 --- a/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.cs +++ b/src/Features/Core/Portable/SolutionCrawler/WorkCoordinator.cs @@ -771,7 +771,13 @@ public int GetDocumentCount(Solution solution) { var project = solution.GetProject(documentId.ProjectId); if (project != null) - yield return (project, documentId); + { + // ReanalyzeScopes are created and held in a queue before they are processed later; it's possible the document + // that we queued for is no longer present. + if (project.ContainsDocument(documentId)) + yield return (project, documentId); + } + break; } } diff --git a/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs b/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs index 99c77bc334599..ed11e7e242821 100644 --- a/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs +++ b/src/Features/Core/Portable/SpellCheck/AbstractSpellCheckCodeFixProvider.cs @@ -113,17 +113,20 @@ private async Task CreateSpellCheckCodeIssueAsync( // - It's very unlikely the user would ever misspell a snippet, then use spell-checking to fix it, // then try to invoke the snippet. // - We believe spell-check should only compare what you have typed to what symbol would be offered here. - var options = CompletionOptions.From(document.Project.Solution.Options, document.Project.Language) with + var options = CompletionOptions.Default with { + HideAdvancedMembers = context.Options.HideAdvancedMembers, SnippetsBehavior = SnippetsRule.NeverInclude, ShowItemsFromUnimportedNamespaces = false, - IsExpandedCompletion = false, - TargetTypedCompletionFilter = false + TargetTypedCompletionFilter = false, + ExpandedCompletionBehavior = ExpandedCompletionMode.NonExpandedItemsOnly }; - var (completionList, _) = await service.GetCompletionsInternalAsync( - document, nameToken.SpanStart, options, cancellationToken: cancellationToken).ConfigureAwait(false); - if (completionList == null) + var passThroughOptions = document.Project.Solution.Options; + + var completionList = await service.GetCompletionsAsync( + document, nameToken.SpanStart, options, passThroughOptions, cancellationToken: cancellationToken).ConfigureAwait(false); + if (completionList.Items.IsEmpty) { return; } diff --git a/src/Features/Core/Portable/StringIndentation/IStringIndentationService.cs b/src/Features/Core/Portable/StringIndentation/IStringIndentationService.cs new file mode 100644 index 0000000000000..60f2d3fb01979 --- /dev/null +++ b/src/Features/Core/Portable/StringIndentation/IStringIndentationService.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.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.StringIndentation +{ + internal interface IStringIndentationService : ILanguageService + { + Task> GetStringIndentationRegionsAsync(Document document, TextSpan textSpan, CancellationToken cancellationToken); + } + + internal readonly struct StringIndentationRegion + { + /// + /// The entire span of the indent region. Given code like: + /// + /// + /// var x = """ + /// x + /// y + /// """; + /// + /// + /// The span will be the region between the ^'s in: + /// + /// + /// ^var x = """ + /// x + /// y + /// ^"""; + /// + /// + /// The span must be on the start and end lines of the string literal as those are the only lines with content + /// known to exist. In other words, the lines with content on them may be entire empty (or still shorter than + /// the indent column), so there's no actual position to associate the span with. + /// + /// The start of the span should be the start of the line that the string literal starts on. The end of the + /// span should be at the start of the ending quotes of the literal. + /// + /// The tagger can then use this span to draw a line like so: + /// + /// + /// var x = """ + /// |x + /// |y + /// """; + /// + /// + public readonly TextSpan IndentSpan; + + /// + /// Regions of the literal that count as 'code holes' and which the lines of the tagger should not draw through. + /// For example, given code like: + /// + /// + /// var x = $""" + /// x + /// { + /// 1 + 1 + /// } xcont + /// y + /// { + /// 2 + 2 + /// } ycont + /// z + /// """; + /// + /// + /// Then there will be two holes demarcated by the ^'s in the following: + /// + /// + /// var x = $""" + /// x + /// ^{ + /// 1 + 1 + /// }^ xcont + /// y + /// ^{ + /// 2 + 2 + /// }^ ycont + /// z + /// """; + /// + /// + /// If the line draw were to intersect one of these spans it will not be drawn, causing the following to be + /// presented: + /// + /// + /// var x = $""" + /// |x + /// |{ + /// 1 + 1 + /// } xcont + /// |y + /// |{ + /// 2 + 2 + /// } ycont + /// |z + /// """; + /// + /// + /// + public readonly ImmutableArray OrderedHoleSpans; + + public StringIndentationRegion(TextSpan indentSpan, ImmutableArray holeSpans = default) + { + IndentSpan = indentSpan; + OrderedHoleSpans = holeSpans.NullToEmpty().Sort(); + } + } +} diff --git a/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs b/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs index 2ca13963182aa..e51c1efe4dbd3 100644 --- a/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs +++ b/src/Features/Core/Portable/UnifiedSuggestions/UnifiedSuggestedActionsSource.cs @@ -35,7 +35,7 @@ public static async ValueTask> GetFilt Document document, TextSpan selection, CodeActionRequestPriority priority, - bool isBlocking, + CodeActionOptions options, Func addOperationScope, CancellationToken cancellationToken) { @@ -45,7 +45,7 @@ public static async ValueTask> GetFilt document, selection, priority, - isBlocking, + options, addOperationScope, cancellationToken), cancellationToken).ConfigureAwait(false); @@ -388,7 +388,7 @@ public static async Task> GetFilterAnd Document document, TextSpan selection, CodeActionRequestPriority priority, - bool isBlocking, + CodeActionOptions options, Func addOperationScope, bool filterOutsideSelection, CancellationToken cancellationToken) @@ -399,7 +399,7 @@ public static async Task> GetFilterAnd // the UI thread. var refactorings = await Task.Run( () => codeRefactoringService.GetRefactoringsAsync( - document, selection, priority, isBlocking, addOperationScope, + document, selection, priority, options, addOperationScope, cancellationToken), cancellationToken).ConfigureAwait(false); var filteredRefactorings = FilterOnAnyThread(refactorings, selection, filterOutsideSelection); diff --git a/src/Features/Core/Portable/Workspace/CompileTimeSolutionProvider.cs b/src/Features/Core/Portable/Workspace/CompileTimeSolutionProvider.cs index 92e2ef75fe679..83d868caf9472 100644 --- a/src/Features/Core/Portable/Workspace/CompileTimeSolutionProvider.cs +++ b/src/Features/Core/Portable/Workspace/CompileTimeSolutionProvider.cs @@ -8,7 +8,6 @@ using System.Diagnostics; using System.IO; using System.Linq; -using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -45,15 +44,20 @@ public Factory() private const string RazorSourceGeneratorTypeName = "Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator"; private static readonly string s_razorSourceGeneratorFileNamePrefix = Path.Combine(RazorSourceGeneratorAssemblyName, RazorSourceGeneratorTypeName); + private readonly Workspace _workspace; + private readonly object _gate = new(); -#if NETCOREAPP - private readonly ConditionalWeakTable _designTimeToCompileTimeSoution = new(); -#else - // Framework lacks both a .Clear() method. So for Framework we simulate that by just overwriting this with a - // new instance. This happens under a lock, so everyone sees a consistent dictionary. - private ConditionalWeakTable _designTimeToCompileTimeSoution = new(); -#endif + /// + /// Cached compile time solution corresponding to the + /// + private (int DesignTimeSolutionVersion, BranchId DesignTimeSolutionBranch, Solution CompileTimeSolution)? _primaryBranchCompileTimeCache; + + /// + /// Cached compile time solution for a forked branch. This is used primarily by LSP cases where + /// we fork the workspace solution and request diagnostics for the forked solution. + /// + private (int DesignTimeSolutionVersion, BranchId DesignTimeSolutionBranch, Solution CompileTimeSolution)? _forkedBranchCompileTimeCache; public CompileTimeSolutionProvider(Workspace workspace) { @@ -63,14 +67,12 @@ public CompileTimeSolutionProvider(Workspace workspace) { lock (_gate) { -#if NETCOREAPP - _designTimeToCompileTimeSoution.Clear(); -#else - _designTimeToCompileTimeSoution = new(); -#endif + _primaryBranchCompileTimeCache = null; + _forkedBranchCompileTimeCache = null; } } }; + _workspace = workspace; } private static bool IsRazorAnalyzerConfig(TextDocumentState documentState) @@ -80,48 +82,83 @@ public Solution GetCompileTimeSolution(Solution designTimeSolution) { lock (_gate) { - if (!_designTimeToCompileTimeSoution.TryGetValue(designTimeSolution, out var compileTimeSolution)) + var cachedCompileTimeSolution = GetCachedCompileTimeSolution(designTimeSolution); + + // Design time solution hasn't changed since we calculated the last compile-time solution: + if (cachedCompileTimeSolution != null) + { + return cachedCompileTimeSolution; + } + + using var _1 = ArrayBuilder.GetInstance(out var configIdsToRemove); + using var _2 = ArrayBuilder.GetInstance(out var documentIdsToRemove); + + foreach (var (_, projectState) in designTimeSolution.State.ProjectStates) { - using var _1 = ArrayBuilder.GetInstance(out var configIdsToRemove); - using var _2 = ArrayBuilder.GetInstance(out var documentIdsToRemove); + var anyConfigs = false; - foreach (var (_, projectState) in designTimeSolution.State.ProjectStates) + foreach (var (_, configState) in projectState.AnalyzerConfigDocumentStates.States) { - var anyConfigs = false; - - foreach (var (_, configState) in projectState.AnalyzerConfigDocumentStates.States) + if (IsRazorAnalyzerConfig(configState)) { - if (IsRazorAnalyzerConfig(configState)) - { - configIdsToRemove.Add(configState.Id); - anyConfigs = true; - } + configIdsToRemove.Add(configState.Id); + anyConfigs = true; } + } - // only remove design-time only documents when source-generated ones replace them - if (anyConfigs) + // only remove design-time only documents when source-generated ones replace them + if (anyConfigs) + { + foreach (var (_, documentState) in projectState.DocumentStates.States) { - foreach (var (_, documentState) in projectState.DocumentStates.States) + if (documentState.Attributes.DesignTimeOnly) { - if (documentState.Attributes.DesignTimeOnly) - { - documentIdsToRemove.Add(documentState.Id); - } + documentIdsToRemove.Add(documentState.Id); } } } + } - compileTimeSolution = designTimeSolution - .RemoveAnalyzerConfigDocuments(configIdsToRemove.ToImmutable()) - .RemoveDocuments(documentIdsToRemove.ToImmutable()); + var compileTimeSolution = designTimeSolution + .RemoveAnalyzerConfigDocuments(configIdsToRemove.ToImmutable()) + .RemoveDocuments(documentIdsToRemove.ToImmutable()); - _designTimeToCompileTimeSoution.Add(designTimeSolution, compileTimeSolution); - } + UpdateCachedCompileTimeSolution(designTimeSolution, compileTimeSolution); return compileTimeSolution; } } + private Solution? GetCachedCompileTimeSolution(Solution designTimeSolution) + { + // If the design time solution is for the primary branch, retrieve the last cached solution for it. + // Otherwise this is a forked solution, so retrieve the last forked compile time solution we calculated. + var cachedCompileTimeSolution = designTimeSolution.BranchId == _workspace.PrimaryBranchId ? _primaryBranchCompileTimeCache : _forkedBranchCompileTimeCache; + + // Verify that the design time solution has not changed since the last calculated compile time solution and that + // the design time solution branch matches the branch of the design time solution we calculated the compile time solution for. + if (cachedCompileTimeSolution != null + && designTimeSolution.WorkspaceVersion == cachedCompileTimeSolution.Value.DesignTimeSolutionVersion + && designTimeSolution.BranchId == cachedCompileTimeSolution.Value.DesignTimeSolutionBranch) + { + return cachedCompileTimeSolution.Value.CompileTimeSolution; + } + + return null; + } + + private void UpdateCachedCompileTimeSolution(Solution designTimeSolution, Solution compileTimeSolution) + { + if (designTimeSolution.BranchId == _workspace.PrimaryBranchId) + { + _primaryBranchCompileTimeCache = (designTimeSolution.WorkspaceVersion, designTimeSolution.BranchId, compileTimeSolution); + } + else + { + _forkedBranchCompileTimeCache = (designTimeSolution.WorkspaceVersion, designTimeSolution.BranchId, compileTimeSolution); + } + } + // Copied from // https://github.com/dotnet/sdk/blob/main/src/RazorSdk/SourceGenerators/RazorSourceGenerator.Helpers.cs#L32 private static string GetIdentifierFromPath(string filePath) diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf index 7c1b1f08579e3..11f807f7bc928 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf @@ -405,6 +405,11 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Změna viditelnosti {0} vyžaduje restartování aplikace. + + Comments not allowed + Comments not allowed + + Configure {0} code style Nakonfigurovat styl kódu {0} @@ -425,6 +430,11 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Nakonfigurujte závažnost pro všechny analyzátory. + + Constructors not allowed + Constructors not allowed + + Convert to LINQ Převést na LINQ @@ -545,6 +555,11 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Změny provedené v projektu {0} vyžadují restartování aplikace: {1} + + Enable JSON editor features + Enable JSON editor features + + Error while reading file '{0}': {1} Při čtení souboru {0} došlo k chybě: {1} @@ -560,6 +575,11 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Při vytváření instance CodeFixProvider {0} došlo k chybě. + + Error parsing comment + Error parsing comment + + Error reading PDB: '{0}' Chyba při čtení PDB: {0} @@ -730,6 +750,16 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Znak \ na konci vzorku je neplatný. This is an error message shown to the user when they write an invalid Regular Expression. Example: \ + + Illegal string character + Illegal string character + + + + Illegal whitespace character + Illegal whitespace character + + Illegal {x,y} with x > y Neplatné {x,y} s x > y @@ -870,16 +900,51 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Zavést proměnnou dotazu + + Invalid JSON pattern + Invalid JSON pattern + + + + Invalid constructor name + Invalid constructor name + + + + Invalid escape sequence + Invalid escape sequence + + Invalid group name: Group names must begin with a word character Neplatný název skupiny: Názvy skupin musí začínat znakem slova. This is an error message shown to the user when they write an invalid Regular Expression. Example: (?<a >a) + + Invalid number + Invalid number + + + + Invalid property name + Invalid property name + + + + Invalid regex pattern + Invalid regex pattern + + Invalid selection. Neplatný výběr + + JSON issue: {0} + JSON issue: {0} + + Make class 'abstract' Nastavit třídu jako abstract @@ -955,6 +1020,11 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Chybí řídicí znak This is an error message shown to the user when they write an invalid Regular Expression. Example: \c + + Missing property value + Missing property value + + Modifying {0} which contains a static variable requires restarting the application. Úprava {0} se statickou proměnnou vyžaduje restartování aplikace. @@ -1070,11 +1140,21 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Přesunutí {0} vyžaduje restartování aplikace. + + Name expected + Name expected + + Navigating to symbol '{0}' from '{1}'. Přechází se na symbol {0} z {1}. + + Nested properties not allowed + Nested properties not allowed + + Nested quantifier {0} Vnořený kvantifikátor {0} @@ -1105,11 +1185,31 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn Nedostatek znaků ) This is an error message shown to the user when they write an invalid Regular Expression. Example: (a + + Only properties allowed in an object + Only properties allowed in an object + + Operators Operátory + + Probable JSON string detected + Probable JSON string detected + + + + Properties not allowed in an array + Properties not allowed in an array + + + + Property name must be a string + Property name must be a string + + Property reference cannot be updated Odkaz na vlastnost se nedá aktualizovat. @@ -2352,7 +2452,7 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv Silent - Silent + Tichý @@ -2385,6 +2485,11 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv Stream musí podporovat operace read a seek. + + Strings must start with " not ' + Strings must start with " not ' + + Suppress {0} Potlačit {0} @@ -2400,6 +2505,11 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv V cestě sestavení {0} byl nalezen symbol. + + Syntax error + Syntax error + + TODO: free unmanaged resources (unmanaged objects) and override finalizer TODO: Uvolněte nespravované prostředky (nespravované objekty) a přepište finalizační metodu. @@ -2445,6 +2555,11 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv Příliš mnoho znaků ) This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Trailing comma not allowed + Trailing comma not allowed + + Types: Typy: @@ -2485,11 +2600,21 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv Nedokončená sada [] This is an error message shown to the user when they write an invalid Regular Expression. Example: [ + + Unterminated comment + Unterminated comment + + Unterminated (?#...) comment Neukončený komentář (?#...) This is an error message shown to the user when they write an invalid Regular Expression. Example: (?# + + Unterminated string + Unterminated string + + Unwrap all arguments Zrušit zalomení všech argumentů @@ -2650,6 +2775,11 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv Hodnota: + + Value required + Value required + + Warning: Changing namespace may produce invalid code and change code meaning. Upozornění: Změna oboru názvů může vést k vytvoření neplatného kódu a změnit význam kódu. @@ -2735,6 +2865,11 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv {0} - {1} + + '{0}' expected + '{0}' expected + + '{0}' found in embedded PDB. Ve vloženém souboru PDB se našel {0}. @@ -2780,11 +2915,21 @@ Pozitivní kontrolní výrazy zpětného vyhledávání s nulovou délkou se obv {0} tady není null. + + '{0}' literal not allowed + '{0}' literal not allowed + + '{0}' may be null here. {0} tady může být null. + + '{0}' unexpected + '{0}' unexpected + + 10,000,000ths of a second Desetimiliontiny sekundy diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf index f37fa60af4881..de7d4a5fa518b 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf @@ -405,6 +405,11 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Das Ändern der Sichtbarkeit von {0} erfordert einen Neustart der Anwendung. + + Comments not allowed + Comments not allowed + + Configure {0} code style Codeformat "{0}" konfigurieren @@ -425,6 +430,11 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Schweregrad für alle Analysetools konfigurieren + + Constructors not allowed + Constructors not allowed + + Convert to LINQ In LINQ konvertieren @@ -545,6 +555,11 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Änderungen, die im Projekt "{0}" vorgenommen wurden, erfordern einen Neustart der Anwendung: {1} + + Enable JSON editor features + Enable JSON editor features + + Error while reading file '{0}': {1} Fehler beim Lesen der Datei "{0}": {1} @@ -560,6 +575,11 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Fehler beim Erstellen der CodeFixProvider-Instanz "{0}". + + Error parsing comment + Error parsing comment + + Error reading PDB: '{0}' Fehler beim Lesen von PDB-Dateien: „{0}“ @@ -730,6 +750,16 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Nicht zulässiges \-Zeichen am Ende des Musters. This is an error message shown to the user when they write an invalid Regular Expression. Example: \ + + Illegal string character + Illegal string character + + + + Illegal whitespace character + Illegal whitespace character + + Illegal {x,y} with x > y Illegaler {x,y}-Wert mit x > y. @@ -870,16 +900,51 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Abfragevariable bereitstellen + + Invalid JSON pattern + Invalid JSON pattern + + + + Invalid constructor name + Invalid constructor name + + + + Invalid escape sequence + Invalid escape sequence + + Invalid group name: Group names must begin with a word character Ungültiger Gruppenname: Gruppennamen müssen mit einem Wortzeichen beginnen. This is an error message shown to the user when they write an invalid Regular Expression. Example: (?<a >a) + + Invalid number + Invalid number + + + + Invalid property name + Invalid property name + + + + Invalid regex pattern + Invalid regex pattern + + Invalid selection. Ungültige Auswahl. + + JSON issue: {0} + JSON issue: {0} + + Make class 'abstract' Klasse als "abstract" festlegen @@ -955,6 +1020,11 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Fehlendes Steuerzeichen This is an error message shown to the user when they write an invalid Regular Expression. Example: \c + + Missing property value + Missing property value + + Modifying {0} which contains a static variable requires restarting the application. Das Ändern von {0}, welche eine statische Variable enthält erfordert einen Neustart der Anwendung. @@ -1070,11 +1140,21 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Das Verschieben von {0} erfordert einen Neustart der Anwendung. + + Name expected + Name expected + + Navigating to symbol '{0}' from '{1}'. Die Navigation von „{1}“ zum Symbol „{0}“ wird durchgeführt. + + Nested properties not allowed + Nested properties not allowed + + Nested quantifier {0} Geschachtelter Quantifizierer {0}. @@ -1105,11 +1185,31 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d Zu wenige )-Zeichen This is an error message shown to the user when they write an invalid Regular Expression. Example: (a + + Only properties allowed in an object + Only properties allowed in an object + + Operators Operatoren + + Probable JSON string detected + Probable JSON string detected + + + + Properties not allowed in an array + Properties not allowed in an array + + + + Property name must be a string + Property name must be a string + + Property reference cannot be updated Der Eigenschaftenverweis kann nicht aktualisiert werden. @@ -2385,6 +2485,11 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg Stream muss Lese- und Suchvorgänge unterstützen. + + Strings must start with " not ' + Strings must start with " not ' + + Suppress {0} {0} unterdrücken @@ -2400,6 +2505,11 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg Das Symbol wurde unter dem Assemblypfad „{0}“ gefunden + + Syntax error + Syntax error + + TODO: free unmanaged resources (unmanaged objects) and override finalizer TODO: Nicht verwaltete Ressourcen (nicht verwaltete Objekte) freigeben und Finalizer überschreiben @@ -2445,6 +2555,11 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg Zu viele )-Zeichen. This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Trailing comma not allowed + Trailing comma not allowed + + Types: Typen: @@ -2485,11 +2600,21 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg Nicht abgeschlossener []-Satz This is an error message shown to the user when they write an invalid Regular Expression. Example: [ + + Unterminated comment + Unterminated comment + + Unterminated (?#...) comment Nicht abgeschlossener (?#...)-Kommentar. This is an error message shown to the user when they write an invalid Regular Expression. Example: (?# + + Unterminated string + Unterminated string + + Unwrap all arguments Umbruch für alle Argumente aufheben @@ -2650,6 +2775,11 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg Wert: + + Value required + Value required + + Warning: Changing namespace may produce invalid code and change code meaning. Warnung: Durch die Änderung des Namespaces kann der Code ungültig werden oder seine Bedeutung verändern. @@ -2735,6 +2865,11 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg {0} - {1} + + '{0}' expected + '{0}' expected + + '{0}' found in embedded PDB. „{0}“ wurde in einer eingebetteten PDB-Datei gefunden. @@ -2780,11 +2915,21 @@ Positive Lookbehindassertionen mit Nullbreite werden normalerweise am Anfang reg "{0}" ist hier nicht NULL. + + '{0}' literal not allowed + '{0}' literal not allowed + + '{0}' may be null here. "{0}" darf hier NULL sein. + + '{0}' unexpected + '{0}' unexpected + + 10,000,000ths of a second 10.000.000stel einer Sekunde @@ -3767,7 +3912,7 @@ Möchten Sie fortfahren? Note: Tab twice to insert the '{0}' snippet. - Hinweis: Drücken Sie zweimal die TAB-TASTE, um den Ausschnitt "{0}" einzufügen. + Hinweis: Drücken Sie zweimal die TAB-TASTE, um den Schnipsel "{0}" einzufügen. @@ -4352,7 +4497,7 @@ Diese Version wird verwendet in: {2} Snippets - Codeausschnitte + Codeschnipsel diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf index 1b3a2701ef342..0d17ba1b38e5f 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf @@ -405,6 +405,11 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Para cambiar la visibilidad de {0} es necesario reiniciar la aplicación. + + Comments not allowed + Comments not allowed + + Configure {0} code style Configurar el estilo de código de {0} @@ -425,6 +430,11 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Configurar la gravedad de todos los analizadores + + Constructors not allowed + Constructors not allowed + + Convert to LINQ Convertir a LINQ @@ -545,6 +555,11 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Los cambios realizados en el proyecto "{0}" requieren reiniciar la aplicación: {1} + + Enable JSON editor features + Enable JSON editor features + + Error while reading file '{0}': {1} Error al leer el archivo "{0}": {1} @@ -560,6 +575,11 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Error al crear la instancia de CodeFixProvider "{0}" + + Error parsing comment + Error parsing comment + + Error reading PDB: '{0}' Error al leer PDB: '{0}' @@ -730,6 +750,16 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa \ no válido al final del modelo This is an error message shown to the user when they write an invalid Regular Expression. Example: \ + + Illegal string character + Illegal string character + + + + Illegal whitespace character + Illegal whitespace character + + Illegal {x,y} with x > y Ilegales {x, y} con x > y @@ -870,16 +900,51 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Introducir la variable de consulta + + Invalid JSON pattern + Invalid JSON pattern + + + + Invalid constructor name + Invalid constructor name + + + + Invalid escape sequence + Invalid escape sequence + + Invalid group name: Group names must begin with a word character Nombre de grupo no válido: nombres de grupo deben comenzar con un carácter de palabra This is an error message shown to the user when they write an invalid Regular Expression. Example: (?<a >a) + + Invalid number + Invalid number + + + + Invalid property name + Invalid property name + + + + Invalid regex pattern + Invalid regex pattern + + Invalid selection. Selección no válida. + + JSON issue: {0} + JSON issue: {0} + + Make class 'abstract' Convertir la clase en "abstract" @@ -955,6 +1020,11 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Falta de carácter de control This is an error message shown to the user when they write an invalid Regular Expression. Example: \c + + Missing property value + Missing property value + + Modifying {0} which contains a static variable requires restarting the application. Para modificar {0}que contiene una variable estática, es necesario reiniciar la aplicación. @@ -1070,11 +1140,21 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa Para mover {0} es necesario reiniciar la aplicación. + + Name expected + Name expected + + Navigating to symbol '{0}' from '{1}'. Navegando al símbolo '{0}' desde '{1}'. + + Nested properties not allowed + Nested properties not allowed + + Nested quantifier {0} Cuantificador anidado {0} @@ -1105,11 +1185,31 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa No hay suficientes ) This is an error message shown to the user when they write an invalid Regular Expression. Example: (a + + Only properties allowed in an object + Only properties allowed in an object + + Operators Operadores + + Probable JSON string detected + Probable JSON string detected + + + + Properties not allowed in an array + Properties not allowed in an array + + + + Property name must be a string + Property name must be a string + + Property reference cannot be updated No se puede actualizar la referencia de propiedad @@ -2385,6 +2485,11 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us La secuencia debe admitir las operaciones de lectura y búsqueda. + + Strings must start with " not ' + Strings must start with " not ' + + Suppress {0} Suprimir {0} @@ -2400,6 +2505,11 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us Símbolo encontrado en la ruta de acceso del ensamblado '{0}' + + Syntax error + Syntax error + + TODO: free unmanaged resources (unmanaged objects) and override finalizer TODO: liberar los recursos no administrados (objetos no administrados) y reemplazar el finalizador @@ -2445,6 +2555,11 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us Demasiados ) This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Trailing comma not allowed + Trailing comma not allowed + + Types: Tipos: @@ -2485,11 +2600,21 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us Conjunto [] sin terminar This is an error message shown to the user when they write an invalid Regular Expression. Example: [ + + Unterminated comment + Unterminated comment + + Unterminated (?#...) comment Comentario (?#...) sin terminar This is an error message shown to the user when they write an invalid Regular Expression. Example: (?# + + Unterminated string + Unterminated string + + Unwrap all arguments Desajustar todos los argumentos @@ -2650,6 +2775,11 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us Valor: + + Value required + Value required + + Warning: Changing namespace may produce invalid code and change code meaning. Advertencia: si cambia Cambiar el espacio de nombres puede producir código inválido y cambiar el significado del código. @@ -2735,6 +2865,11 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us {0} - {1} + + '{0}' expected + '{0}' expected + + '{0}' found in embedded PDB. '{0}' encontrados en PDB incrustado. @@ -2780,11 +2915,21 @@ Las aserciones de búsqueda retrasada (lookbehind) positivas de ancho cero se us "{0}" no es NULL aquí. + + '{0}' literal not allowed + '{0}' literal not allowed + + '{0}' may be null here. "{0}" puede ser NULL aquí. + + '{0}' unexpected + '{0}' unexpected + + 10,000,000ths of a second La diezmillonésima parte de un segundo diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf index 461c9bb1d6429..dc6213cd3ee28 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf @@ -405,6 +405,11 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai La modification de la visibilité de {0} requiert le redémarrage de l’application. + + Comments not allowed + Comments not allowed + + Configure {0} code style Configurer le style de code {0} @@ -425,6 +430,11 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Configurer la gravité pour tous les analyseurs + + Constructors not allowed + Constructors not allowed + + Convert to LINQ Convertir en LINQ @@ -545,6 +555,11 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Les modifications apportées au projet « {0} » nécessitent le redémarrage de l’application : {1} + + Enable JSON editor features + Enable JSON editor features + + Error while reading file '{0}': {1} Erreur durant la lecture du fichier '{0}' : {1} @@ -560,6 +575,11 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Erreur lors de la création de l'instance de CodeFixProvider '{0}' + + Error parsing comment + Error parsing comment + + Error reading PDB: '{0}' Erreur de lecture de la base de données PDB : '{0}' @@ -730,6 +750,16 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Caractère \ non autorisé à la fin du modèle This is an error message shown to the user when they write an invalid Regular Expression. Example: \ + + Illegal string character + Illegal string character + + + + Illegal whitespace character + Illegal whitespace character + + Illegal {x,y} with x > y {x,y} non autorisé avec x > y @@ -870,16 +900,51 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Introduire la variable de requête + + Invalid JSON pattern + Invalid JSON pattern + + + + Invalid constructor name + Invalid constructor name + + + + Invalid escape sequence + Invalid escape sequence + + Invalid group name: Group names must begin with a word character Nom de groupe non valide : les noms de groupe doivent commencer par un caractère alphabétique This is an error message shown to the user when they write an invalid Regular Expression. Example: (?<a >a) + + Invalid number + Invalid number + + + + Invalid property name + Invalid property name + + + + Invalid regex pattern + Invalid regex pattern + + Invalid selection. Sélection incorrecte. + + JSON issue: {0} + JSON issue: {0} + + Make class 'abstract' Rendre la classe 'abstract' @@ -955,6 +1020,11 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Caractère de contrôle manquant This is an error message shown to the user when they write an invalid Regular Expression. Example: \c + + Missing property value + Missing property value + + Modifying {0} which contains a static variable requires restarting the application. La modification de {0} qui contient une variable statique requiert le redémarrage de l’application. @@ -1070,11 +1140,21 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Le déplacement de {0} requiert le redémarrage de l’application. + + Name expected + Name expected + + Navigating to symbol '{0}' from '{1}'. Navigation vers le symbole '{0}' à partir de '{1}'. + + Nested properties not allowed + Nested properties not allowed + + Nested quantifier {0} Quantificateur imbriqué {0} @@ -1105,11 +1185,31 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai Pas assez de )'s This is an error message shown to the user when they write an invalid Regular Expression. Example: (a + + Only properties allowed in an object + Only properties allowed in an object + + Operators Opérateurs + + Probable JSON string detected + Probable JSON string detected + + + + Properties not allowed in an array + Properties not allowed in an array + + + + Property name must be a string + Property name must be a string + + Property reference cannot be updated La référence de propriété ne peut pas être mise à jour @@ -2385,6 +2485,11 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée Le flux doit prendre en charge les opérations de lecture et de recherche. + + Strings must start with " not ' + Strings must start with " not ' + + Suppress {0} Supprimer {0} @@ -2400,6 +2505,11 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée Symbole trouvé dans le chemin d’accès de l’assembly '{0}' + + Syntax error + Syntax error + + TODO: free unmanaged resources (unmanaged objects) and override finalizer TODO: libérer les ressources non managées (objets non managés) et substituer le finaliseur @@ -2445,6 +2555,11 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée Trop de )'s This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Trailing comma not allowed + Trailing comma not allowed + + Types: Types : @@ -2485,11 +2600,21 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée Ensemble [] inachevé This is an error message shown to the user when they write an invalid Regular Expression. Example: [ + + Unterminated comment + Unterminated comment + + Unterminated (?#...) comment Commentaire (?#...) non terminé This is an error message shown to the user when they write an invalid Regular Expression. Example: (?# + + Unterminated string + Unterminated string + + Unwrap all arguments Désenvelopper tous les arguments @@ -2650,6 +2775,11 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée Valeur : + + Value required + Value required + + Warning: Changing namespace may produce invalid code and change code meaning. Avertissement : Le changement d’espace de noms peut produire du code non valide et changer la signification du code. @@ -2735,6 +2865,11 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée {0} - {1} + + '{0}' expected + '{0}' expected + + '{0}' found in embedded PDB. '{0}' trouvé dans le fichier PDB incorporé. @@ -2780,11 +2915,21 @@ Les assertions arrière positives de largeur nulle sont généralement utilisée '{0}' n'a pas une valeur null ici. + + '{0}' literal not allowed + '{0}' literal not allowed + + '{0}' may be null here. '{0}' a peut-être une valeur null ici. + + '{0}' unexpected + '{0}' unexpected + + 10,000,000ths of a second 10 000 000es de seconde diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf index 37be60cf20496..81a03a477060a 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf @@ -405,6 +405,11 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Se si modifica la visibilità di {0}, è necessario riavviare l'applicazione. + + Comments not allowed + Comments not allowed + + Configure {0} code style Configura lo stile del codice di {0} @@ -425,6 +430,11 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Configura la gravità per tutti gli analizzatori + + Constructors not allowed + Constructors not allowed + + Convert to LINQ Converti in LINQ @@ -545,6 +555,11 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Le modifiche apportate nel progetto '{0}' richiedono il riavvio dell'applicazione: {1} + + Enable JSON editor features + Enable JSON editor features + + Error while reading file '{0}': {1} Si è verificato un errore durante la lettura del file '{0}': {1} @@ -560,6 +575,11 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Si è verificato un errore durante la creazione dell'istanza di CodeFixProvider '{0}' + + Error parsing comment + Error parsing comment + + Error reading PDB: '{0}' Errore durante la lettura del PDB: '{0}' @@ -730,6 +750,16 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Carattere \ non valido alla fine del criterio This is an error message shown to the user when they write an invalid Regular Expression. Example: \ + + Illegal string character + Illegal string character + + + + Illegal whitespace character + Illegal whitespace character + + Illegal {x,y} with x > y {x,y} non valido con x > y @@ -870,16 +900,51 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Introduci la variabile di query + + Invalid JSON pattern + Invalid JSON pattern + + + + Invalid constructor name + Invalid constructor name + + + + Invalid escape sequence + Invalid escape sequence + + Invalid group name: Group names must begin with a word character Nome di gruppo non valido: i nomi di gruppo devono iniziare con un carattere alfanumerico This is an error message shown to the user when they write an invalid Regular Expression. Example: (?<a >a) + + Invalid number + Invalid number + + + + Invalid property name + Invalid property name + + + + Invalid regex pattern + Invalid regex pattern + + Invalid selection. Selezione non valida. + + JSON issue: {0} + JSON issue: {0} + + Make class 'abstract' Rendi la classe 'abstract' @@ -955,6 +1020,11 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Carattere di controllo mancante This is an error message shown to the user when they write an invalid Regular Expression. Example: \c + + Missing property value + Missing property value + + Modifying {0} which contains a static variable requires restarting the application. Se si modifica {0} che contiene una variabile statica, è necessario riavviare l'applicazione. @@ -1070,11 +1140,21 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Se si sposta {0}, è necessario riavviare l'applicazione. + + Name expected + Name expected + + Navigating to symbol '{0}' from '{1}'. Passaggio al simbolo '{0}' da '{1}'. + + Nested properties not allowed + Nested properties not allowed + + Nested quantifier {0} Quantificatore nidificato {0} @@ -1105,11 +1185,31 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa Parentesi chiuse insufficienti This is an error message shown to the user when they write an invalid Regular Expression. Example: (a + + Only properties allowed in an object + Only properties allowed in an object + + Operators Operatori + + Probable JSON string detected + Probable JSON string detected + + + + Properties not allowed in an array + Properties not allowed in an array + + + + Property name must be a string + Property name must be a string + + Property reference cannot be updated Non è possibile aggiornare il riferimento alla proprietà @@ -2385,6 +2485,11 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' Il flusso deve supportare operazioni di lettura e ricerca. + + Strings must start with " not ' + Strings must start with " not ' + + Suppress {0} Elimina {0} @@ -2400,6 +2505,11 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' Simbolo trovato nel percorso assembly '{0}' + + Syntax error + Syntax error + + TODO: free unmanaged resources (unmanaged objects) and override finalizer TODO: liberare risorse non gestite (oggetti non gestiti) ed eseguire l'override del finalizzatore @@ -2445,6 +2555,11 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' Troppe parentesi di chiusura This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Trailing comma not allowed + Trailing comma not allowed + + Types: Tipi: @@ -2485,11 +2600,21 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' Set di [] senza terminazione This is an error message shown to the user when they write an invalid Regular Expression. Example: [ + + Unterminated comment + Unterminated comment + + Unterminated (?#...) comment Commento (?#...) senza terminazione This is an error message shown to the user when they write an invalid Regular Expression. Example: (?# + + Unterminated string + Unterminated string + + Unwrap all arguments Annulla il ritorno a capo per tutti gli argomenti @@ -2650,6 +2775,11 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' Valore: + + Value required + Value required + + Warning: Changing namespace may produce invalid code and change code meaning. Avviso: la modifica dello spazio dei nomi può comportare la creazione di codice non valido e modificare il significato del codice. @@ -2735,6 +2865,11 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' {0} - {1} + + '{0}' expected + '{0}' expected + + '{0}' found in embedded PDB. '{0}' trovati nel PDB incorporato. @@ -2780,11 +2915,21 @@ Le asserzioni lookbehind positive di larghezza zero vengono usate in genere all' '{0}' non è Null in questo punto. + + '{0}' literal not allowed + '{0}' literal not allowed + + '{0}' may be null here. '{0}' può essere Null in questo punto. + + '{0}' unexpected + '{0}' unexpected + + 10,000,000ths of a second Decimilionesimi di secondo diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf index ca2c7e0fc26b5..20926fc78e9fb 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf @@ -405,6 +405,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma {0} の可視性を変更するには、アプリケーションを再起動する必要があります。 + + Comments not allowed + Comments not allowed + + Configure {0} code style {0} コード スタイルの構成 @@ -425,6 +430,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma すべてのアナライザーの重要度を構成します + + Constructors not allowed + Constructors not allowed + + Convert to LINQ LINQ に変換 @@ -545,6 +555,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma プロジェクト '{0}' で加えられた変更にはアプリケーションの再起動が必要です: {1} + + Enable JSON editor features + Enable JSON editor features + + Error while reading file '{0}': {1} ファイル {0}' の読み取り中にエラーが発生しました: {1} @@ -560,6 +575,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma CodeFixProvider '{0}' のインスタンスの作成でエラーが発生しました + + Error parsing comment + Error parsing comment + + Error reading PDB: '{0}' PDB: '{0}' の読み込み中にエラーが発生した @@ -730,6 +750,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 無効\末尾のパターン This is an error message shown to the user when they write an invalid Regular Expression. Example: \ + + Illegal string character + Illegal string character + + + + Illegal whitespace character + Illegal whitespace character + + Illegal {x,y} with x > y {x,y} で x > y は無効です @@ -870,16 +900,51 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma クエリ変数を導入します + + Invalid JSON pattern + Invalid JSON pattern + + + + Invalid constructor name + Invalid constructor name + + + + Invalid escape sequence + Invalid escape sequence + + Invalid group name: Group names must begin with a word character 無効なグループ名: グループ名は単語文字で始める必要があります This is an error message shown to the user when they write an invalid Regular Expression. Example: (?<a >a) + + Invalid number + Invalid number + + + + Invalid property name + Invalid property name + + + + Invalid regex pattern + Invalid regex pattern + + Invalid selection. 選択が無効です。 + + JSON issue: {0} + JSON issue: {0} + + Make class 'abstract' クラスを 'abstract' にしてください @@ -955,6 +1020,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma コントロール文字がありません This is an error message shown to the user when they write an invalid Regular Expression. Example: \c + + Missing property value + Missing property value + + Modifying {0} which contains a static variable requires restarting the application. 静的な変数を含む {0} を変更するには、アプリケーションを再起動する必要があります。 @@ -1070,11 +1140,21 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma {0} を移動するには、アプリケーションを再起動する必要があります。 + + Name expected + Name expected + + Navigating to symbol '{0}' from '{1}'. "{1}" からシンボル '{0}' に移動しています。 + + Nested properties not allowed + Nested properties not allowed + + Nested quantifier {0} 入れ子になった量指定子 {0} @@ -1105,11 +1185,31 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma ) が足りません This is an error message shown to the user when they write an invalid Regular Expression. Example: (a + + Only properties allowed in an object + Only properties allowed in an object + + Operators 演算子 + + Probable JSON string detected + Probable JSON string detected + + + + Properties not allowed in an array + Properties not allowed in an array + + + + Property name must be a string + Property name must be a string + + Property reference cannot be updated プロパティ参照を更新できません @@ -2385,6 +2485,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of ストリームは、読み取りとシーク操作をサポートする必要があります。 + + Strings must start with " not ' + Strings must start with " not ' + + Suppress {0} {0} の非表示 @@ -2400,6 +2505,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of アセンブリ パス '{0}' にシンボルが見つかりました + + Syntax error + Syntax error + + TODO: free unmanaged resources (unmanaged objects) and override finalizer TODO: アンマネージド リソース (アンマネージド オブジェクト) を解放し、ファイナライザーをオーバーライドします @@ -2445,6 +2555,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of ) が多すぎます This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Trailing comma not allowed + Trailing comma not allowed + + Types: 型: @@ -2485,11 +2600,21 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 未終了の [] セットです This is an error message shown to the user when they write an invalid Regular Expression. Example: [ + + Unterminated comment + Unterminated comment + + Unterminated (?#...) comment 未終了の (?#...) コメントです This is an error message shown to the user when they write an invalid Regular Expression. Example: (?# + + Unterminated string + Unterminated string + + Unwrap all arguments すべての引数の折り返しを解除 @@ -2650,6 +2775,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 値: + + Value required + Value required + + Warning: Changing namespace may produce invalid code and change code meaning. 警告: 名前空間を変更すると無効なコードが生成され、コードの意味が変更される可能性があります。 @@ -2735,6 +2865,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of {0} - {1} + + '{0}' expected + '{0}' expected + + '{0}' found in embedded PDB. 埋め込み PDB に '{0}' が見つかりました。 @@ -2780,11 +2915,21 @@ Zero-width positive lookbehind assertions are typically used at the beginning of ここでは、'{0}' は null ではありません。 + + '{0}' literal not allowed + '{0}' literal not allowed + + '{0}' may be null here. ここでは、'{0}' は null である可能性があります。 + + '{0}' unexpected + '{0}' unexpected + + 10,000,000ths of a second 10,000,000 分の 1 秒単位 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf index da2341fce4044..e504b06b3bbb1 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf @@ -405,6 +405,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma {0} 표시 유형을 변경하려면 애플리케이션을 다시 시작해야 합니다. + + Comments not allowed + Comments not allowed + + Configure {0} code style {0} 코드 스타일 구성 @@ -425,6 +430,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 모든 분석기에 대해 심각도 구성 + + Constructors not allowed + Constructors not allowed + + Convert to LINQ LINQ로 변환 @@ -545,6 +555,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma ' {0}' 프로젝트에서 변경한 내용을 적용하려면 응용 프로그램 ‘{1}’을(를) 다시 시작 해야 합니다. + + Enable JSON editor features + Enable JSON editor features + + Error while reading file '{0}': {1} '{0}' 파일을 읽는 동안 오류가 발생했습니다. {1} @@ -560,6 +575,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma CodeFixProvider '{0}' 인스턴스를 만드는 동안 오류가 발생했습니다. + + Error parsing comment + Error parsing comment + + Error reading PDB: '{0}' PDB를 읽는 동안 오류 발생: '{0}' @@ -730,6 +750,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 패턴 끝에 \를 사용할 수 없습니다. This is an error message shown to the user when they write an invalid Regular Expression. Example: \ + + Illegal string character + Illegal string character + + + + Illegal whitespace character + Illegal whitespace character + + Illegal {x,y} with x > y x > y인 잘못된 {x,y}입니다. @@ -870,16 +900,51 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 쿼리 변수 지정 + + Invalid JSON pattern + Invalid JSON pattern + + + + Invalid constructor name + Invalid constructor name + + + + Invalid escape sequence + Invalid escape sequence + + Invalid group name: Group names must begin with a word character 잘못된 그룹 이름: 그룹 이름은 단어 문자로 시작해야 합니다. This is an error message shown to the user when they write an invalid Regular Expression. Example: (?<a >a) + + Invalid number + Invalid number + + + + Invalid property name + Invalid property name + + + + Invalid regex pattern + Invalid regex pattern + + Invalid selection. 잘못된 선택 항목입니다. + + JSON issue: {0} + JSON issue: {0} + + Make class 'abstract' 'abstract' 클래스 만들기 @@ -955,6 +1020,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 제어 문자가 없습니다. This is an error message shown to the user when they write an invalid Regular Expression. Example: \c + + Missing property value + Missing property value + + Modifying {0} which contains a static variable requires restarting the application. 정적 변수를 포함하는 {0}을(를) 수정하려면 애플리케이션을 다시 시작해야 합니다. @@ -1070,11 +1140,21 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma {0}을(를) 이동하려면 애플리케이션을 다시 시작해야 합니다. + + Name expected + Name expected + + Navigating to symbol '{0}' from '{1}'. '{1}'에서 기호 '{0}'(으)로 이동하는 중입니다. + + Nested properties not allowed + Nested properties not allowed + + Nested quantifier {0} 중첩 수량자 {0}입니다. @@ -1105,11 +1185,31 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 부족 )'s This is an error message shown to the user when they write an invalid Regular Expression. Example: (a + + Only properties allowed in an object + Only properties allowed in an object + + Operators 연산자 + + Probable JSON string detected + Probable JSON string detected + + + + Properties not allowed in an array + Properties not allowed in an array + + + + Property name must be a string + Property name must be a string + + Property reference cannot be updated 속성 참조를 업데이트할 수 없습니다. @@ -2385,6 +2485,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 스트림은 읽기 및 찾기 작업을 지원해야 합니다. + + Strings must start with " not ' + Strings must start with " not ' + + Suppress {0} {0}을(를) 표시하지 않음 @@ -2400,6 +2505,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 어셈블리 경로 '{0}'에서 기호를 찾음 + + Syntax error + Syntax error + + TODO: free unmanaged resources (unmanaged objects) and override finalizer TODO: 비관리형 리소스(비관리형 개체)를 해제하고 종료자를 재정의합니다. @@ -2445,6 +2555,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of )가 너무 많습니다. This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Trailing comma not allowed + Trailing comma not allowed + + Types: 형식: @@ -2485,11 +2600,21 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 종결되지 않은 [] 집합 This is an error message shown to the user when they write an invalid Regular Expression. Example: [ + + Unterminated comment + Unterminated comment + + Unterminated (?#...) comment 종격되지 않은 (?#...) 주석 This is an error message shown to the user when they write an invalid Regular Expression. Example: (?# + + Unterminated string + Unterminated string + + Unwrap all arguments 모든 인수 래핑 해제 @@ -2650,6 +2775,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 값: + + Value required + Value required + + Warning: Changing namespace may produce invalid code and change code meaning. 경고: 네임스페이스를 변경하면 잘못된 코드가 발생하고 코드 의미가 변경될 수 있습니다. @@ -2735,6 +2865,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of {0} - {1} + + '{0}' expected + '{0}' expected + + '{0}' found in embedded PDB. 포함된 PDB에서 '{0}'을(를) 찾았습니다. @@ -2780,11 +2915,21 @@ Zero-width positive lookbehind assertions are typically used at the beginning of '{0}'은(는) 여기에서 null이 아닙니다. + + '{0}' literal not allowed + '{0}' literal not allowed + + '{0}' may be null here. '{0}'은(는) 여기에서 null일 수 있습니다. + + '{0}' unexpected + '{0}' unexpected + + 10,000,000ths of a second 10,000,000분의 1초 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf index ca0c8d5f25aa4..504d36357504f 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf @@ -405,6 +405,11 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Zmiana widoczności elementu {0} wymaga ponownego uruchomienia aplikacji. + + Comments not allowed + Comments not allowed + + Configure {0} code style Konfiguruj styl kodu {0} @@ -425,6 +430,11 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Konfiguruj ważność wszystkich analizatorów + + Constructors not allowed + Constructors not allowed + + Convert to LINQ Konwertuj na składnię LINQ @@ -545,6 +555,11 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Zmiany wprowadzone w projekcie „{0}” wymagają ponownego uruchomienia aplikacji: {1} + + Enable JSON editor features + Enable JSON editor features + + Error while reading file '{0}': {1} Błąd podczas odczytywania pliku „{0}”: {1} @@ -560,6 +575,11 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Błąd podczas tworzenia wystąpienia elementu CodeFixProvider „{0}” + + Error parsing comment + Error parsing comment + + Error reading PDB: '{0}' Błąd podczas odczytywania pliku PDB: „{0}” @@ -730,6 +750,16 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Niedozwolony znak \ na końcu wzorca This is an error message shown to the user when they write an invalid Regular Expression. Example: \ + + Illegal string character + Illegal string character + + + + Illegal whitespace character + Illegal whitespace character + + Illegal {x,y} with x > y Niedozwolone wyrażenie {x,y} z wartością x > y @@ -870,16 +900,51 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Wprowadź zmienną zapytania + + Invalid JSON pattern + Invalid JSON pattern + + + + Invalid constructor name + Invalid constructor name + + + + Invalid escape sequence + Invalid escape sequence + + Invalid group name: Group names must begin with a word character Nieprawidłowa nazwa grupy: nazwy grup muszą rozpoczynać się od znaku wyrazu This is an error message shown to the user when they write an invalid Regular Expression. Example: (?<a >a) + + Invalid number + Invalid number + + + + Invalid property name + Invalid property name + + + + Invalid regex pattern + Invalid regex pattern + + Invalid selection. Nieprawidłowe zaznaczenie. + + JSON issue: {0} + JSON issue: {0} + + Make class 'abstract' Ustaw specyfikator „abstract” dla klasy @@ -955,6 +1020,11 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Brak znaku kontrolnego This is an error message shown to the user when they write an invalid Regular Expression. Example: \c + + Missing property value + Missing property value + + Modifying {0} which contains a static variable requires restarting the application. Modyfikacja elementu {0}, który zawiera zmienną statyczną, wymaga ponownego uruchomienia aplikacji. @@ -1070,11 +1140,21 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Przeniesienie elementu {0} wymaga ponownego uruchomienia aplikacji. + + Name expected + Name expected + + Navigating to symbol '{0}' from '{1}'. Trwa przechodzenie do symbolu „{0}” z „{1}”. + + Nested properties not allowed + Nested properties not allowed + + Nested quantifier {0} Zagnieżdżony kwantyfikator {0} @@ -1105,11 +1185,31 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k Zbyt mało znaków ) This is an error message shown to the user when they write an invalid Regular Expression. Example: (a + + Only properties allowed in an object + Only properties allowed in an object + + Operators Operatory + + Probable JSON string detected + Probable JSON string detected + + + + Properties not allowed in an array + Properties not allowed in an array + + + + Property name must be a string + Property name must be a string + + Property reference cannot be updated Nie można zaktualizować referencji właściwości @@ -2385,6 +2485,11 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk Strumień musi obsługiwać operacje odczytu i wyszukiwania. + + Strings must start with " not ' + Strings must start with " not ' + + Suppress {0} Pomiń element {0} @@ -2400,6 +2505,11 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk Znaleziono symbol w ścieżce zestawu „{0}” + + Syntax error + Syntax error + + TODO: free unmanaged resources (unmanaged objects) and override finalizer TODO: Zwolnić niezarządzane zasoby (niezarządzane obiekty) i przesłonić finalizator @@ -2445,6 +2555,11 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk Zbyt wiele znaków ) This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Trailing comma not allowed + Trailing comma not allowed + + Types: Typy: @@ -2485,11 +2600,21 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk Niezakończony zestaw [] This is an error message shown to the user when they write an invalid Regular Expression. Example: [ + + Unterminated comment + Unterminated comment + + Unterminated (?#...) comment Niezakończony komentarz (?#...) This is an error message shown to the user when they write an invalid Regular Expression. Example: (?# + + Unterminated string + Unterminated string + + Unwrap all arguments Odwijaj wszystkie argumenty @@ -2650,6 +2775,11 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk Wartość: + + Value required + Value required + + Warning: Changing namespace may produce invalid code and change code meaning. Ostrzeżenie: Zmiana przestrzeni nazw może skutkować nieprawidłowym kodem i zmianą jego znaczenia. @@ -2735,6 +2865,11 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk {0} - {1} + + '{0}' expected + '{0}' expected + + '{0}' found in embedded PDB. Znaleziono „{0}” w osadzonym pliku PDB. @@ -2780,11 +2915,21 @@ Pozytywne asercje wsteczne o zerowej szerokości są zwykle używane na początk Element „{0}” nie ma wartości null w tym miejscu. + + '{0}' literal not allowed + '{0}' literal not allowed + + '{0}' may be null here. Element „{0}” może mieć wartość null w tym miejscu. + + '{0}' unexpected + '{0}' unexpected + + 10,000,000ths of a second 1/10 000 000 sekundy diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf index a1ddedb268287..9672ebdf431f9 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf @@ -405,6 +405,11 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Para alterar a visibilidade de {0}, é necessário reiniciar o aplicativo. + + Comments not allowed + Comments not allowed + + Configure {0} code style Configurar estilo de código de {0} @@ -425,6 +430,11 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Configurar gravidade para todos os analisadores + + Constructors not allowed + Constructors not allowed + + Convert to LINQ Converter para LINQ @@ -545,6 +555,11 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess As alterações feitas no projeto '{0}' requerem a reinicialização do aplicativo: {1} + + Enable JSON editor features + Enable JSON editor features + + Error while reading file '{0}': {1} Erro ao ler o arquivo '{0}': {1} @@ -560,6 +575,11 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Erro ao criar instância de CodeFixProvider '{0}' + + Error parsing comment + Error parsing comment + + Error reading PDB: '{0}' Erro ao ler PDB: '{0}' @@ -730,6 +750,16 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess \ ilegal no final do padrão This is an error message shown to the user when they write an invalid Regular Expression. Example: \ + + Illegal string character + Illegal string character + + + + Illegal whitespace character + Illegal whitespace character + + Illegal {x,y} with x > y {x,y} ilegal com x> y @@ -870,16 +900,51 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Introduzir a variável de consulta + + Invalid JSON pattern + Invalid JSON pattern + + + + Invalid constructor name + Invalid constructor name + + + + Invalid escape sequence + Invalid escape sequence + + Invalid group name: Group names must begin with a word character Nome de grupo inválido: nomes de grupos devem começar com um caractere de palavra This is an error message shown to the user when they write an invalid Regular Expression. Example: (?<a >a) + + Invalid number + Invalid number + + + + Invalid property name + Invalid property name + + + + Invalid regex pattern + Invalid regex pattern + + Invalid selection. Seleção inválida. + + JSON issue: {0} + JSON issue: {0} + + Make class 'abstract' Tornar a classe 'abstract' @@ -955,6 +1020,11 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Caractere de controle ausente This is an error message shown to the user when they write an invalid Regular Expression. Example: \c + + Missing property value + Missing property value + + Modifying {0} which contains a static variable requires restarting the application. A modificação de {0}, que contém uma variável estática, requer o reinício do aplicativo. @@ -1070,11 +1140,21 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Mover {0} requer reiniciar o aplicativo. + + Name expected + Name expected + + Navigating to symbol '{0}' from '{1}'. Navegando para o símbolo '{0}' de '{1}'. + + Nested properties not allowed + Nested properties not allowed + + Nested quantifier {0} Quantificador aninhado {0} @@ -1105,11 +1185,31 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess Não há )'s suficientes This is an error message shown to the user when they write an invalid Regular Expression. Example: (a + + Only properties allowed in an object + Only properties allowed in an object + + Operators Operadores + + Probable JSON string detected + Probable JSON string detected + + + + Properties not allowed in an array + Properties not allowed in an array + + + + Property name must be a string + Property name must be a string + + Property reference cannot be updated A referência de propriedade não pode ser atualizada @@ -2385,6 +2485,11 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas O fluxo deve fornecer suporte a operações de leitura e busca. + + Strings must start with " not ' + Strings must start with " not ' + + Suppress {0} Suprimir {0} @@ -2400,6 +2505,11 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas Símbolo encontrado no caminho de montagem '{0}' + + Syntax error + Syntax error + + TODO: free unmanaged resources (unmanaged objects) and override finalizer TODO: free unmanaged resources (unmanaged objects) and override finalizer @@ -2445,6 +2555,11 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas Muitos )'s This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Trailing comma not allowed + Trailing comma not allowed + + Types: Tipos: @@ -2485,11 +2600,21 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas Conjunto [] não finalizado This is an error message shown to the user when they write an invalid Regular Expression. Example: [ + + Unterminated comment + Unterminated comment + + Unterminated (?#...) comment Comentário (?#...) não finalizado This is an error message shown to the user when they write an invalid Regular Expression. Example: (?# + + Unterminated string + Unterminated string + + Unwrap all arguments Desencapsular todos os argumentos @@ -2650,6 +2775,11 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas Valor: + + Value required + Value required + + Warning: Changing namespace may produce invalid code and change code meaning. Aviso: a alteração do namespace pode produzir código inválido e mudar o significado do código. @@ -2735,6 +2865,11 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas {0} - {1} + + '{0}' expected + '{0}' expected + + '{0}' found in embedded PDB. '{0}' encontrado no PDB integrado. @@ -2780,11 +2915,21 @@ As declarações de lookbehind positivas de largura zero normalmente são usadas '{0}' não é nulo aqui. + + '{0}' literal not allowed + '{0}' literal not allowed + + '{0}' may be null here. '{0}' pode ser nulo aqui. + + '{0}' unexpected + '{0}' unexpected + + 10,000,000ths of a second Dez milionésimos de um segundo diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf index 056492df1c31b..96c526bd28221 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf @@ -405,6 +405,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Для изменения видимости {0} требуется перезапустить приложение. + + Comments not allowed + Comments not allowed + + Configure {0} code style Настройка стиля кода {0} @@ -425,6 +430,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Настройка серьезности для всех анализаторов + + Constructors not allowed + Constructors not allowed + + Convert to LINQ Преобразовать в LINQ @@ -545,6 +555,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma После внесения изменений в проект "{0}" необходимо перезапустить приложение: {1} + + Enable JSON editor features + Enable JSON editor features + + Error while reading file '{0}': {1} Ошибка при чтении файла "{0}": {1} @@ -560,6 +575,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Ошибка при создании экземпляра CodeFixProvider "{0}". + + Error parsing comment + Error parsing comment + + Error reading PDB: '{0}' Ошибка чтения PDB-файла: "{0}" @@ -730,6 +750,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Недопустимый символ "\" в конце шаблона This is an error message shown to the user when they write an invalid Regular Expression. Example: \ + + Illegal string character + Illegal string character + + + + Illegal whitespace character + Illegal whitespace character + + Illegal {x,y} with x > y Неправильное использование {x,y} в x > y @@ -870,16 +900,51 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Добавить переменную запроса + + Invalid JSON pattern + Invalid JSON pattern + + + + Invalid constructor name + Invalid constructor name + + + + Invalid escape sequence + Invalid escape sequence + + Invalid group name: Group names must begin with a word character Недопустимое имя группы: имя группы должно начинаться с буквы This is an error message shown to the user when they write an invalid Regular Expression. Example: (?<a >a) + + Invalid number + Invalid number + + + + Invalid property name + Invalid property name + + + + Invalid regex pattern + Invalid regex pattern + + Invalid selection. Недопустимое выделение. + + JSON issue: {0} + JSON issue: {0} + + Make class 'abstract' Сделать класс абстрактным @@ -955,6 +1020,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Отсутствует управляющий символ This is an error message shown to the user when they write an invalid Regular Expression. Example: \c + + Missing property value + Missing property value + + Modifying {0} which contains a static variable requires restarting the application. Для изменения {0}, где содержится статическая переменная, требуется перезапустить приложение. @@ -1070,11 +1140,21 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Для перемещения {0} требуется перезапустить приложение. + + Name expected + Name expected + + Navigating to symbol '{0}' from '{1}'. Переход к символу "{0}" от "{1}". + + Nested properties not allowed + Nested properties not allowed + + Nested quantifier {0} Вложенный квантификатор {0} @@ -1105,11 +1185,31 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma Отсутствуют закрывающие круглые скобки This is an error message shown to the user when they write an invalid Regular Expression. Example: (a + + Only properties allowed in an object + Only properties allowed in an object + + Operators Операторы + + Probable JSON string detected + Probable JSON string detected + + + + Properties not allowed in an array + Properties not allowed in an array + + + + Property name must be a string + Property name must be a string + + Property reference cannot be updated Не удается обновить ссылку на свойство @@ -2385,6 +2485,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Поток должен поддерживать операции чтения и поиска. + + Strings must start with " not ' + Strings must start with " not ' + + Suppress {0} Скрыть {0} @@ -2400,6 +2505,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Найден символ в пути сборки "{0}" + + Syntax error + Syntax error + + TODO: free unmanaged resources (unmanaged objects) and override finalizer TODO: освободить неуправляемые ресурсы (неуправляемые объекты) и переопределить метод завершения @@ -2445,6 +2555,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Слишком много закрывающих круглых скобок This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Trailing comma not allowed + Trailing comma not allowed + + Types: Типы: @@ -2485,11 +2600,21 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Набор [] без признака завершения This is an error message shown to the user when they write an invalid Regular Expression. Example: [ + + Unterminated comment + Unterminated comment + + Unterminated (?#...) comment Незавершенный комментарий (? #...) This is an error message shown to the user when they write an invalid Regular Expression. Example: (?# + + Unterminated string + Unterminated string + + Unwrap all arguments Развернуть все аргументы @@ -2650,6 +2775,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Значение: + + Value required + Value required + + Warning: Changing namespace may produce invalid code and change code meaning. Предупреждение: изменение пространства имен может привести к появлению недопустимого кода и к изменению значения кода. @@ -2735,6 +2865,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of {0} - {1} + + '{0}' expected + '{0}' expected + + '{0}' found in embedded PDB. Найдено "{0}" во внедренном PDB-файле. @@ -2780,11 +2915,21 @@ Zero-width positive lookbehind assertions are typically used at the beginning of Здесь "{0}" имеет значение, отличное от NULL. + + '{0}' literal not allowed + '{0}' literal not allowed + + '{0}' may be null here. Здесь "{0}" может иметь значение NULL. + + '{0}' unexpected + '{0}' unexpected + + 10,000,000ths of a second 10 000 000-е доли секунды diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf index 9b6b513ed3e45..31d684c4ebd48 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf @@ -405,6 +405,11 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be {0} öğesinin görünürlüğünün değiştirilmesi, uygulamanın yeniden başlatılmasını gerektirir. + + Comments not allowed + Comments not allowed + + Configure {0} code style {0} kod stilini yapılandır @@ -425,6 +430,11 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Tüm çözümleyiciler için önem derecesini yapılandır + + Constructors not allowed + Constructors not allowed + + Convert to LINQ LINQ to dönüştürme @@ -545,6 +555,11 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be '{0}' projesinde yapılan değişiklikler uygulamanın yeniden başlatılmasını gerektiriyor: {1} + + Enable JSON editor features + Enable JSON editor features + + Error while reading file '{0}': {1} '{0}' dosyası okunurken hata: {1} @@ -560,6 +575,11 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be '{0}' CodeFixProvider örneği oluşturulurken hata oluştu + + Error parsing comment + Error parsing comment + + Error reading PDB: '{0}' PDB okuma hatası: “{0}” @@ -730,6 +750,16 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Yasadışı \ model sonunda This is an error message shown to the user when they write an invalid Regular Expression. Example: \ + + Illegal string character + Illegal string character + + + + Illegal whitespace character + Illegal whitespace character + + Illegal {x,y} with x > y Yasadışı {x, y} x > y @@ -870,16 +900,51 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Sorgu değişkeni ekle + + Invalid JSON pattern + Invalid JSON pattern + + + + Invalid constructor name + Invalid constructor name + + + + Invalid escape sequence + Invalid escape sequence + + Invalid group name: Group names must begin with a word character Geçersiz grup adı: grup adları bir sözcük karakteri ile başlamalıdır This is an error message shown to the user when they write an invalid Regular Expression. Example: (?<a >a) + + Invalid number + Invalid number + + + + Invalid property name + Invalid property name + + + + Invalid regex pattern + Invalid regex pattern + + Invalid selection. Geçersiz seçim. + + JSON issue: {0} + JSON issue: {0} + + Make class 'abstract' Sınıfı 'abstract' yap @@ -955,6 +1020,11 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Eksik denetim karakteri This is an error message shown to the user when they write an invalid Regular Expression. Example: \c + + Missing property value + Missing property value + + Modifying {0} which contains a static variable requires restarting the application. Statik bir değişken içeren {0} öğesinin değiştirilmesi, uygulamanın yeniden başlatılmasını gerektirir. @@ -1070,11 +1140,21 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be {0} öğesinin taşınması uygulamanın yeniden başlatılmasını gerektirir. + + Name expected + Name expected + + Navigating to symbol '{0}' from '{1}'. “{1}“den "{0}" sembolüne gidiliyor. + + Nested properties not allowed + Nested properties not allowed + + Nested quantifier {0} İç içe geçmiş niceleyici {0} @@ -1105,11 +1185,31 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be Değil yeterli)'ın This is an error message shown to the user when they write an invalid Regular Expression. Example: (a + + Only properties allowed in an object + Only properties allowed in an object + + Operators Operatörler + + Probable JSON string detected + Probable JSON string detected + + + + Properties not allowed in an array + Properties not allowed in an array + + + + Property name must be a string + Property name must be a string + + Property reference cannot be updated Özellik başvurusu güncelleştirilemiyor @@ -2385,6 +2485,11 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri Akış okuma ve arama işlemlerini desteklemelidir. + + Strings must start with " not ' + Strings must start with " not ' + + Suppress {0} {0} eylemini bastır @@ -2400,6 +2505,11 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri “{0}” derleme yolunda sembol bulundu + + Syntax error + Syntax error + + TODO: free unmanaged resources (unmanaged objects) and override finalizer TODO: yönetilmeyen kaynakları (yönetilmeyen nesneleri) serbest bırakın ve sonlandırıcıyı geçersiz kılın @@ -2445,6 +2555,11 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri Çok fazla)'s This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Trailing comma not allowed + Trailing comma not allowed + + Types: Türler: @@ -2485,11 +2600,21 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri Sonlandırılmamış [] kümesi This is an error message shown to the user when they write an invalid Regular Expression. Example: [ + + Unterminated comment + Unterminated comment + + Unterminated (?#...) comment Sonlandırılmamış (?... #) yorum This is an error message shown to the user when they write an invalid Regular Expression. Example: (?# + + Unterminated string + Unterminated string + + Unwrap all arguments Tüm bağımsız değişkenlerin sarmalamasını kaldır @@ -2650,6 +2775,11 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri Değer: + + Value required + Value required + + Warning: Changing namespace may produce invalid code and change code meaning. Uyarı: Ad alanının değiştirilmesi geçersiz kod oluşturabilir ve kodun anlamını değiştirebilir. @@ -2735,6 +2865,11 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri {0} - {1} + + '{0}' expected + '{0}' expected + + '{0}' found in embedded PDB. “{0}”, gömülü PDB'de bulundu. @@ -2780,11 +2915,21 @@ Sıfır genişlikli pozitif geri yönlü onaylamalar genellikle normal ifadeleri '{0}' burada null değil. + + '{0}' literal not allowed + '{0}' literal not allowed + + '{0}' may be null here. '{0}' burada null olabilir. + + '{0}' unexpected + '{0}' unexpected + + 10,000,000ths of a second Saniyenin 10.000.000'da biri diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf index 7ee893d23e7bb..2c0a7371e64b9 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf @@ -405,6 +405,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 更改 {0} 的可见性要求重启应用程序。 + + Comments not allowed + Comments not allowed + + Configure {0} code style 配置 {0} 代码样式 @@ -425,6 +430,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 为所有分析器配置严重性 + + Constructors not allowed + Constructors not allowed + + Convert to LINQ 转换为 LINQ @@ -545,6 +555,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 在项目“{0}”中所做的更改要求重新启动应用程序: {1} + + Enable JSON editor features + Enable JSON editor features + + Error while reading file '{0}': {1} 读取文件“{0}”时出错: {1} @@ -560,6 +575,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 创建 CodeFixProvider“{0}”的实例时出错 + + Error parsing comment + Error parsing comment + + Error reading PDB: '{0}' 读取 PDB 时出错:“{0}” @@ -730,6 +750,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 模式末尾的 \ 非法 This is an error message shown to the user when they write an invalid Regular Expression. Example: \ + + Illegal string character + Illegal string character + + + + Illegal whitespace character + Illegal whitespace character + + Illegal {x,y} with x > y x > y 的 {x,y} 无效 @@ -870,16 +900,51 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 引入查询变量 + + Invalid JSON pattern + Invalid JSON pattern + + + + Invalid constructor name + Invalid constructor name + + + + Invalid escape sequence + Invalid escape sequence + + Invalid group name: Group names must begin with a word character 组名无效: 组名必须以单词字符开头 This is an error message shown to the user when they write an invalid Regular Expression. Example: (?<a >a) + + Invalid number + Invalid number + + + + Invalid property name + Invalid property name + + + + Invalid regex pattern + Invalid regex pattern + + Invalid selection. 无效的选择。 + + JSON issue: {0} + JSON issue: {0} + + Make class 'abstract' 将类设置为 "abstract" @@ -955,6 +1020,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 缺少控制字符 This is an error message shown to the user when they write an invalid Regular Expression. Example: \c + + Missing property value + Missing property value + + Modifying {0} which contains a static variable requires restarting the application. 修改包含静态变量的 {0} 需要重启应用程序。 @@ -1070,11 +1140,21 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 移动 {0} 要求重启应用程序。 + + Name expected + Name expected + + Navigating to symbol '{0}' from '{1}'. 从“{1}”导航到符号“{0}”。 + + Nested properties not allowed + Nested properties not allowed + + Nested quantifier {0} 嵌套限定符 {0} @@ -1105,11 +1185,31 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma ")" 不足 This is an error message shown to the user when they write an invalid Regular Expression. Example: (a + + Only properties allowed in an object + Only properties allowed in an object + + Operators 运算符 + + Probable JSON string detected + Probable JSON string detected + + + + Properties not allowed in an array + Properties not allowed in an array + + + + Property name must be a string + Property name must be a string + + Property reference cannot be updated 无法更新属性引用 @@ -2385,6 +2485,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 流必须支持读取和搜寻操作。 + + Strings must start with " not ' + Strings must start with " not ' + + Suppress {0} 抑制 {0} @@ -2400,6 +2505,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 在程序集路径 "{0}" 中找到符号 + + Syntax error + Syntax error + + TODO: free unmanaged resources (unmanaged objects) and override finalizer TODO: 释放未托管的资源(未托管的对象)并重写终结器 @@ -2445,6 +2555,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of ")" 太多 This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Trailing comma not allowed + Trailing comma not allowed + + Types: 类型: @@ -2485,11 +2600,21 @@ Zero-width positive lookbehind assertions are typically used at the beginning of [] 集未关闭 This is an error message shown to the user when they write an invalid Regular Expression. Example: [ + + Unterminated comment + Unterminated comment + + Unterminated (?#...) comment (?#...) 注释未关闭 This is an error message shown to the user when they write an invalid Regular Expression. Example: (?# + + Unterminated string + Unterminated string + + Unwrap all arguments 展开所有参数 @@ -2650,6 +2775,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 值: + + Value required + Value required + + Warning: Changing namespace may produce invalid code and change code meaning. 警告: 更改命名空间可能会产生无效的代码并更改代码的含义。 @@ -2735,6 +2865,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of {0} - {1} + + '{0}' expected + '{0}' expected + + '{0}' found in embedded PDB. 在嵌入的 PDB 中找到“{0}”。 @@ -2780,11 +2915,21 @@ Zero-width positive lookbehind assertions are typically used at the beginning of “{0}”在此处不为 null。 + + '{0}' literal not allowed + '{0}' literal not allowed + + '{0}' may be null here. “{0}”可能在此处为 null。 + + '{0}' unexpected + '{0}' unexpected + + 10,000,000ths of a second 千万分之一秒 diff --git a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf index f35e8c169d6da..32bcdb2757ee6 100644 --- a/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf +++ b/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf @@ -405,6 +405,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 變更 {0} 的可見度需要重新啟動應用程式。 + + Comments not allowed + Comments not allowed + + Configure {0} code style 設定 {0} 程式碼樣式 @@ -425,6 +430,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 設定所有分析器的嚴重性 + + Constructors not allowed + Constructors not allowed + + Convert to LINQ 轉換至 LINQ @@ -545,6 +555,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 在專案 '{0}' 中所做的變更需要重新啟動應用程式: {1} + + Enable JSON editor features + Enable JSON editor features + + Error while reading file '{0}': {1} 讀取檔案 '{0}' 時發生錯誤: {1} @@ -560,6 +575,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 建立 CodeFixProvider '{0}' 的執行個體時發生錯誤 + + Error parsing comment + Error parsing comment + + Error reading PDB: '{0}' 讀取 PDB 時發生錯誤: '{0}' @@ -730,6 +750,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 模式結尾使用 \ 不符合格式規定 This is an error message shown to the user when they write an invalid Regular Expression. Example: \ + + Illegal string character + Illegal string character + + + + Illegal whitespace character + Illegal whitespace character + + Illegal {x,y} with x > y x 大於 y 的 {x,y} 不符合格式 @@ -870,16 +900,51 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 引進查詢變數 + + Invalid JSON pattern + Invalid JSON pattern + + + + Invalid constructor name + Invalid constructor name + + + + Invalid escape sequence + Invalid escape sequence + + Invalid group name: Group names must begin with a word character 群組名稱無效: 群組名稱必須以文字字元開頭 This is an error message shown to the user when they write an invalid Regular Expression. Example: (?<a >a) + + Invalid number + Invalid number + + + + Invalid property name + Invalid property name + + + + Invalid regex pattern + Invalid regex pattern + + Invalid selection. 無效的選取範圍。 + + JSON issue: {0} + JSON issue: {0} + + Make class 'abstract' 將類別設為 'abstract' @@ -955,6 +1020,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 缺少控制字元 This is an error message shown to the user when they write an invalid Regular Expression. Example: \c + + Missing property value + Missing property value + + Modifying {0} which contains a static variable requires restarting the application. 修改包含靜態變數的 {0} 需要重新啟動應用程式。 @@ -1070,11 +1140,21 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma 移動 {0} 需要重新啟動應用程式。 + + Name expected + Name expected + + Navigating to symbol '{0}' from '{1}'. 正在從 '{1}' 瀏覽至符號 '{0}'。 + + Nested properties not allowed + Nested properties not allowed + + Nested quantifier {0} 巢狀數量詞 {0} @@ -1105,11 +1185,31 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma ) 不夠 This is an error message shown to the user when they write an invalid Regular Expression. Example: (a + + Only properties allowed in an object + Only properties allowed in an object + + Operators 運算子 + + Probable JSON string detected + Probable JSON string detected + + + + Properties not allowed in an array + Properties not allowed in an array + + + + Property name must be a string + Property name must be a string + + Property reference cannot be updated 無法更新屬性參考 @@ -2385,6 +2485,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 資料流必須支援讀取及搜尋作業。 + + Strings must start with " not ' + Strings must start with " not ' + + Suppress {0} 隱藏 {0} @@ -2400,6 +2505,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 在組件路徑 '{0}' 中找到符號 + + Syntax error + Syntax error + + TODO: free unmanaged resources (unmanaged objects) and override finalizer TODO: 釋出非受控資源 (非受控物件) 並覆寫完成項 @@ -2445,6 +2555,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 太多 ) This is an error message shown to the user when they write an invalid Regular Expression. Example: ) + + Trailing comma not allowed + Trailing comma not allowed + + Types: 類型: @@ -2485,11 +2600,21 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 未結束的 [] 組合 This is an error message shown to the user when they write an invalid Regular Expression. Example: [ + + Unterminated comment + Unterminated comment + + Unterminated (?#...) comment 未結束的 (?#...) 註解 This is an error message shown to the user when they write an invalid Regular Expression. Example: (?# + + Unterminated string + Unterminated string + + Unwrap all arguments 將所有引數取消換行 @@ -2650,6 +2775,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of 值: + + Value required + Value required + + Warning: Changing namespace may produce invalid code and change code meaning. 警告: 變更命名空間可能會產生無效的程式碼及變更程式碼意義。 @@ -2735,6 +2865,11 @@ Zero-width positive lookbehind assertions are typically used at the beginning of {0} - {1} + + '{0}' expected + '{0}' expected + + '{0}' found in embedded PDB. 在內嵌 PDB 中找到 '{0}'。 @@ -2780,11 +2915,21 @@ Zero-width positive lookbehind assertions are typically used at the beginning of '{0}' 在此不是 null。 + + '{0}' literal not allowed + '{0}' literal not allowed + + '{0}' may be null here. '{0}' 在此可能為 null。 + + '{0}' unexpected + '{0}' unexpected + + 10,000,000ths of a second 1/10,000,000 秒 diff --git a/src/Features/LanguageServer/Protocol/AbstractRequestDispatcherFactory.cs b/src/Features/LanguageServer/Protocol/AbstractRequestDispatcherFactory.cs index 55a1483d4bff6..28a2cc4d88769 100644 --- a/src/Features/LanguageServer/Protocol/AbstractRequestDispatcherFactory.cs +++ b/src/Features/LanguageServer/Protocol/AbstractRequestDispatcherFactory.cs @@ -25,9 +25,9 @@ protected AbstractRequestDispatcherFactory(IEnumerable - public virtual RequestDispatcher CreateRequestDispatcher(ImmutableArray supportedLanguages) + public virtual RequestDispatcher CreateRequestDispatcher(ImmutableArray supportedLanguages, WellKnownLspServerKinds serverKind) { - return new RequestDispatcher(_requestHandlerProviders, supportedLanguages); + return new RequestDispatcher(_requestHandlerProviders, supportedLanguages, serverKind); } } } diff --git a/src/Features/LanguageServer/Protocol/CSharpVisualBasicLanguageServerFactory.cs b/src/Features/LanguageServer/Protocol/CSharpVisualBasicLanguageServerFactory.cs index fbe3979234d33..51c7ad4947537 100644 --- a/src/Features/LanguageServer/Protocol/CSharpVisualBasicLanguageServerFactory.cs +++ b/src/Features/LanguageServer/Protocol/CSharpVisualBasicLanguageServerFactory.cs @@ -15,8 +15,6 @@ namespace Microsoft.CodeAnalysis.LanguageServer [Export(typeof(ILanguageServerFactory)), Shared] internal class CSharpVisualBasicLanguageServerFactory : ILanguageServerFactory { - public const string UserVisibleName = "Roslyn Language Server Client"; - private readonly RequestDispatcherFactory _dispatcherFactory; private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; private readonly IAsynchronousOperationListenerProvider _listenerProvider; @@ -54,8 +52,7 @@ public ILanguageServerTarget Create( logger, ProtocolConstants.RoslynLspLanguages, clientName: null, - userVisibleServerName: UserVisibleName, - telemetryServerTypeName: this.GetType().Name); + WellKnownLspServerKinds.CSharpVisualBasicLspServer); } } } diff --git a/src/Features/LanguageServer/Protocol/Extensions/Extensions.cs b/src/Features/LanguageServer/Protocol/Extensions/Extensions.cs index 2d72c6c2f4110..677ad1b413f56 100644 --- a/src/Features/LanguageServer/Protocol/Extensions/Extensions.cs +++ b/src/Features/LanguageServer/Protocol/Extensions/Extensions.cs @@ -15,13 +15,17 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Text.Adornments; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer { internal static class Extensions { public static Uri GetURI(this TextDocument document) - => ProtocolConversions.GetUriFromFilePath(document.FilePath); + { + Contract.ThrowIfNull(document.FilePath); + return ProtocolConversions.GetUriFromFilePath(document.FilePath); + } public static Uri? TryGetURI(this TextDocument document, RequestContext? context = null) => ProtocolConversions.TryGetUriFromFilePath(document.FilePath, context); diff --git a/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs b/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs index 2f5615180fb92..77d236e7b8151 100644 --- a/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs +++ b/src/Features/LanguageServer/Protocol/Extensions/ProtocolConversions.cs @@ -141,7 +141,7 @@ static async Task GetInsertionCharacterAsync(Document document, int positi } } - public static Uri GetUriFromFilePath(string? filePath) + public static Uri GetUriFromFilePath(string filePath) { if (filePath is null) throw new ArgumentNullException(nameof(filePath)); @@ -367,18 +367,8 @@ static LSP.Location ConvertTextSpanWithTextToLocation(TextSpan span, SourceText } } - public static LSP.CodeDescription? HelpLinkToCodeDescription(string? helpLink) - { - if (Uri.TryCreate(helpLink, UriKind.RelativeOrAbsolute, out var uri)) - { - return new LSP.CodeDescription - { - Href = uri, - }; - } - - return null; - } + public static LSP.CodeDescription? HelpLinkToCodeDescription(Uri? uri) + => (uri != null) ? new LSP.CodeDescription { Href = uri } : null; public static LSP.SymbolKind NavigateToKindToSymbolKind(string kind) { diff --git a/src/Features/LanguageServer/Protocol/Handler/AbstractRequestHandlerProvider.cs b/src/Features/LanguageServer/Protocol/Handler/AbstractRequestHandlerProvider.cs index ef33ac2da19c5..844638db8e4d8 100644 --- a/src/Features/LanguageServer/Protocol/Handler/AbstractRequestHandlerProvider.cs +++ b/src/Features/LanguageServer/Protocol/Handler/AbstractRequestHandlerProvider.cs @@ -20,6 +20,6 @@ internal abstract class AbstractRequestHandlerProvider /// /// Instantiates new handler instances and returns them. /// - public abstract ImmutableArray CreateRequestHandlers(); + public abstract ImmutableArray CreateRequestHandlers(WellKnownLspServerKinds serverKind); } } diff --git a/src/Features/LanguageServer/Protocol/Handler/AbstractStatelessRequestHandler.cs b/src/Features/LanguageServer/Protocol/Handler/AbstractStatelessRequestHandler.cs index e64d722cce8bd..f387fe0c853cd 100644 --- a/src/Features/LanguageServer/Protocol/Handler/AbstractStatelessRequestHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/AbstractStatelessRequestHandler.cs @@ -24,7 +24,7 @@ internal abstract class AbstractStatelessRequestHandler HandleRequestAsync(RequestType request, RequestContext context, CancellationToken cancellationToken); - public override ImmutableArray CreateRequestHandlers() + public override ImmutableArray CreateRequestHandlers(WellKnownLspServerKinds serverKind) { return ImmutableArray.Create(this); } diff --git a/src/Features/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs index 3142f0be16c71..5095f0d19428b 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs @@ -62,7 +62,7 @@ public AbstractGoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSour { if (!typeOnly || symbol is ITypeSymbol) { - var declarationFile = await _metadataAsSourceFileService.GetGeneratedFileAsync(document.Project, symbol, signaturesOnly: true, allowDecompilation: false, cancellationToken).ConfigureAwait(false); + var declarationFile = await _metadataAsSourceFileService.GetGeneratedFileAsync(document.Project, symbol, signaturesOnly: false, allowDecompilation: true, cancellationToken).ConfigureAwait(false); var linePosSpan = declarationFile.IdentifierLocation.GetLineSpan().Span; locations.Add(new LSP.Location diff --git a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs index f669bb8845ce8..897e27f637198 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs @@ -30,6 +30,18 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics /// The LSP type that is returned on completion of the request. internal abstract class AbstractPullDiagnosticHandler : IRequestHandler where TDiagnosticsParams : IPartialResultParams { + /// + /// Diagnostic mode setting for Razor. This should always be as there is no push support in Razor. + /// This option is only for passing to the diagnostics service and can be removed when we switch all of Roslyn to LSP pull. + /// + private static readonly Option2 s_razorDiagnosticMode = new(nameof(InternalDiagnosticsOptions), "RazorDiagnosticMode", defaultValue: DiagnosticMode.Pull); + + /// + /// Diagnostic mode setting for Live Share. This should always be as there is no push support in Live Share. + /// This option is only for passing to the diagnostics service and can be removed when we switch all of Roslyn to LSP pull. + /// + private static readonly Option2 s_liveShareDiagnosticMode = new(nameof(InternalDiagnosticsOptions), "LiveShareDiagnosticMode", defaultValue: DiagnosticMode.Pull); + protected record struct PreviousResult(string PreviousResultId, TextDocumentIdentifier TextDocument); /// @@ -40,6 +52,8 @@ protected record struct PreviousResult(string PreviousResultId, TextDocumentIden protected const int WorkspaceDiagnosticIdentifier = 1; protected const int DocumentDiagnosticIdentifier = 2; + private readonly WellKnownLspServerKinds _serverKind; + protected readonly IDiagnosticService DiagnosticService; /// @@ -75,8 +89,10 @@ protected record struct PreviousResult(string PreviousResultId, TextDocumentIden public bool RequiresLSPSolution => true; protected AbstractPullDiagnosticHandler( + WellKnownLspServerKinds serverKind, IDiagnosticService diagnosticService) { + _serverKind = serverKind; DiagnosticService = diagnosticService; } @@ -104,7 +120,7 @@ protected AbstractPullDiagnosticHandler( /// /// Produce the diagnostics for the specified document. /// - protected abstract Task> GetDiagnosticsAsync(RequestContext context, Document document, Option2 diagnosticMode, CancellationToken cancellationToken); + protected abstract Task> GetDiagnosticsAsync(RequestContext context, Document document, DiagnosticMode diagnosticMode, CancellationToken cancellationToken); /// /// Generate the right diagnostic tags for a particular diagnostic. @@ -209,15 +225,15 @@ private async Task ComputeAndReportCurrentDiagnosticsAsync( ClientCapabilities clientCapabilities, CancellationToken cancellationToken) { - // Being asked about this document for the first time. Or being asked again and we have different - // diagnostics. Compute and report the current diagnostics info for this document. - - // Razor has a separate option for determining if they should be in push or pull mode. - var diagnosticMode = document.IsRazorDocument() - ? InternalDiagnosticsOptions.RazorDiagnosticMode - : InternalDiagnosticsOptions.NormalDiagnosticMode; + var diagnosticModeOption = _serverKind switch + { + WellKnownLspServerKinds.LiveShareLspServer => s_liveShareDiagnosticMode, + WellKnownLspServerKinds.RazorLspServer => s_razorDiagnosticMode, + _ => InternalDiagnosticsOptions.NormalDiagnosticMode, + }; - var isPull = context.GlobalOptions.IsPullDiagnostics(diagnosticMode); + var diagnosticMode = context.GlobalOptions.GetDiagnosticMode(diagnosticModeOption); + var isPull = diagnosticMode == DiagnosticMode.Pull; context.TraceInformation($"Getting '{(isPull ? "pull" : "push")}' diagnostics with mode '{diagnosticMode}'"); @@ -361,7 +377,7 @@ LSP.VSDiagnostic CreateBaseLspDiagnostic() { Source = "Roslyn", Code = diagnosticData.Id, - CodeDescription = ProtocolConversions.HelpLinkToCodeDescription(diagnosticData.HelpLink), + CodeDescription = ProtocolConversions.HelpLinkToCodeDescription(diagnosticData.GetValidHelpLinkUri()), Message = diagnosticData.Message, Severity = ConvertDiagnosticSeverity(diagnosticData.Severity), Range = ProtocolConversions.LinePositionToRange(DiagnosticData.GetLinePositionSpan(diagnosticData.DataLocation, text, useMappedSpan)), diff --git a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/DocumentPullDiagnosticHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/DocumentPullDiagnosticHandler.cs index 6f60253f40474..013c475be2abc 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/DocumentPullDiagnosticHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/DocumentPullDiagnosticHandler.cs @@ -20,9 +20,10 @@ internal class DocumentPullDiagnosticHandler : AbstractPullDiagnosticHandler VSInternalMethods.DocumentPullDiagnosticName; public DocumentPullDiagnosticHandler( + WellKnownLspServerKinds serverKind, IDiagnosticService diagnosticService, IDiagnosticAnalyzerService analyzerService) - : base(diagnosticService) + : base(serverKind, diagnosticService) { _analyzerService = analyzerService; } @@ -63,7 +64,7 @@ protected override ImmutableArray GetOrderedDocuments(RequestContext c } protected override Task> GetDiagnosticsAsync( - RequestContext context, Document document, Option2 diagnosticMode, CancellationToken cancellationToken) + RequestContext context, Document document, DiagnosticMode diagnosticMode, CancellationToken cancellationToken) { // For open documents, directly use the IDiagnosticAnalyzerService. This will use the actual snapshots // we're passing in. If information is already cached for that snapshot, it will be returned. Otherwise, diff --git a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/DocumentPullDiagonsticHandlerProvider.cs b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/DocumentPullDiagonsticHandlerProvider.cs index c3585a4f6fb46..c5842590e6218 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/DocumentPullDiagonsticHandlerProvider.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/DocumentPullDiagonsticHandlerProvider.cs @@ -28,9 +28,9 @@ public DocumentPullDiagonsticHandlerProvider( _analyzerService = analyzerService; } - public override ImmutableArray CreateRequestHandlers() + public override ImmutableArray CreateRequestHandlers(WellKnownLspServerKinds serverKind) { - return ImmutableArray.Create(new DocumentPullDiagnosticHandler(_diagnosticService, _analyzerService)); + return ImmutableArray.Create(new DocumentPullDiagnosticHandler(serverKind, _diagnosticService, _analyzerService)); } } } diff --git a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalDocumentPullDiagnosticHandlerProvider.cs b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalDocumentPullDiagnosticHandlerProvider.cs index 948fb666498aa..f0773bd99cfb1 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalDocumentPullDiagnosticHandlerProvider.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalDocumentPullDiagnosticHandlerProvider.cs @@ -27,8 +27,8 @@ public ExperimentalDocumentPullDiagnosticHandlerProvider( _analyzerService = analyzerService; } - public override ImmutableArray CreateRequestHandlers() + public override ImmutableArray CreateRequestHandlers(WellKnownLspServerKinds serverKind) { - return ImmutableArray.Create(new ExperimentalDocumentPullDiagnosticsHandler(_diagnosticService, _analyzerService)); + return ImmutableArray.Create(new ExperimentalDocumentPullDiagnosticsHandler(serverKind, _diagnosticService, _analyzerService)); } } diff --git a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalDocumentPullDiagnosticsHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalDocumentPullDiagnosticsHandler.cs index f43e56c991451..b7d48945e5727 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalDocumentPullDiagnosticsHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalDocumentPullDiagnosticsHandler.cs @@ -25,9 +25,10 @@ internal class ExperimentalDocumentPullDiagnosticsHandler : AbstractPullDiagnost private readonly IDiagnosticAnalyzerService _analyzerService; public ExperimentalDocumentPullDiagnosticsHandler( + WellKnownLspServerKinds serverKind, IDiagnosticService diagnosticService, IDiagnosticAnalyzerService analyzerService) - : base(diagnosticService) + : base(serverKind, diagnosticService) { _analyzerService = analyzerService; } @@ -62,7 +63,7 @@ protected override DocumentDiagnosticPartialReport CreateReport(TextDocumentIden return null; } - protected override Task> GetDiagnosticsAsync(RequestContext context, Document document, Option2 diagnosticMode, CancellationToken cancellationToken) + protected override Task> GetDiagnosticsAsync(RequestContext context, Document document, DiagnosticMode diagnosticMode, CancellationToken cancellationToken) { // We are intentionally getting diagnostics for the up to date LSP snapshot instead of from the IDiagnosticService // as the solution crawler does not run in VSCode. When the solution crawler is removed from VS, the VS LSP diagnostics diff --git a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalWorkspacePullDiagnosticHandlerProvider.cs b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalWorkspacePullDiagnosticHandlerProvider.cs index 267af2b7233b3..df64fc655442d 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalWorkspacePullDiagnosticHandlerProvider.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalWorkspacePullDiagnosticHandlerProvider.cs @@ -27,8 +27,8 @@ public ExperimentalWorkspacePullDiagnosticHandlerProvider( _analyzerService = analyzerService; } - public override ImmutableArray CreateRequestHandlers() + public override ImmutableArray CreateRequestHandlers(WellKnownLspServerKinds serverKind) { - return ImmutableArray.Create(new ExperimentalWorkspacePullDiagnosticsHandler(_diagnosticService, _analyzerService)); + return ImmutableArray.Create(new ExperimentalWorkspacePullDiagnosticsHandler(serverKind, _diagnosticService, _analyzerService)); } } diff --git a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalWorkspacePullDiagnosticsHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalWorkspacePullDiagnosticsHandler.cs index 48942ac61c635..312352a779b1c 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalWorkspacePullDiagnosticsHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/Experimental/ExperimentalWorkspacePullDiagnosticsHandler.cs @@ -21,9 +21,10 @@ internal class ExperimentalWorkspacePullDiagnosticsHandler : AbstractPullDiagnos private readonly IDiagnosticAnalyzerService _analyzerService; public ExperimentalWorkspacePullDiagnosticsHandler( + WellKnownLspServerKinds serverKind, IDiagnosticService diagnosticService, IDiagnosticAnalyzerService analyzerService) - : base(diagnosticService) + : base(serverKind, diagnosticService) { _analyzerService = analyzerService; } @@ -54,7 +55,7 @@ protected override WorkspaceDiagnosticReport CreateReport(TextDocumentIdentifier return null; } - protected override async Task> GetDiagnosticsAsync(RequestContext context, Document document, Option2 diagnosticMode, CancellationToken cancellationToken) + protected override async Task> GetDiagnosticsAsync(RequestContext context, Document document, DiagnosticMode diagnosticMode, CancellationToken cancellationToken) { var diagnostics = await _analyzerService.GetDiagnosticsForSpanAsync(document, range: null, cancellationToken: cancellationToken).ConfigureAwait(false); return diagnostics; diff --git a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs index f3fd53c73f73e..dda4dcee6b9ff 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/WorkspacePullDiagnosticHandler.cs @@ -20,8 +20,8 @@ internal class WorkspacePullDiagnosticHandler : AbstractPullDiagnosticHandler VSInternalMethods.WorkspacePullDiagnosticName; - public WorkspacePullDiagnosticHandler(IDiagnosticService diagnosticService) - : base(diagnosticService) + public WorkspacePullDiagnosticHandler(WellKnownLspServerKinds serverKind, IDiagnosticService diagnosticService) + : base(serverKind, diagnosticService) { } @@ -55,7 +55,7 @@ protected override ImmutableArray GetOrderedDocuments(RequestContext c } protected override Task> GetDiagnosticsAsync( - RequestContext context, Document document, Option2 diagnosticMode, CancellationToken cancellationToken) + RequestContext context, Document document, DiagnosticMode diagnosticMode, CancellationToken cancellationToken) { // For closed files, go to the IDiagnosticService for results. These won't necessarily be totally up to // date. However, that's fine as these are closed files and won't be in the process of being edited. So diff --git a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/WorkspacePullDiagnosticHandlerProvider.cs b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/WorkspacePullDiagnosticHandlerProvider.cs index 6162d227a80b8..92502896f43bd 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Diagnostics/WorkspacePullDiagnosticHandlerProvider.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Diagnostics/WorkspacePullDiagnosticHandlerProvider.cs @@ -24,9 +24,9 @@ public WorkspacePullDiagnosticHandlerProvider(IDiagnosticService diagnosticServi _diagnosticService = diagnosticService; } - public override ImmutableArray CreateRequestHandlers() + public override ImmutableArray CreateRequestHandlers(WellKnownLspServerKinds serverKind) { - return ImmutableArray.Create(new WorkspacePullDiagnosticHandler(_diagnosticService)); + return ImmutableArray.Create(new WorkspacePullDiagnosticHandler(serverKind, _diagnosticService)); } } } diff --git a/src/Features/LanguageServer/Protocol/Handler/Highlights/DocumentHighlightHandler.cs b/src/Features/LanguageServer/Protocol/Handler/Highlights/DocumentHighlightHandler.cs index 96382e1b918e1..b4ec6691eb9e2 100644 --- a/src/Features/LanguageServer/Protocol/Handler/Highlights/DocumentHighlightHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/Highlights/DocumentHighlightHandler.cs @@ -3,13 +3,17 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Composition; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.DocumentHighlighting; +using Microsoft.CodeAnalysis.Highlighting; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Roslyn.Utilities; @@ -19,10 +23,13 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler [ProvidesMethod(Methods.TextDocumentDocumentHighlightName)] internal class DocumentHighlightsHandler : AbstractStatelessRequestHandler { + private readonly IHighlightingService _highlightingService; + [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public DocumentHighlightsHandler() + public DocumentHighlightsHandler(IHighlightingService highlightingService) { + _highlightingService = highlightingService; } public override string Method => Methods.TextDocumentDocumentHighlightName; @@ -38,10 +45,45 @@ public DocumentHighlightsHandler() if (document == null) return null; - var documentHighlightService = document.Project.LanguageServices.GetRequiredService(); + var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false); - var options = DocumentHighlightingOptions.From(document.Project); + // First check if this is a keyword that needs highlighting. + var keywordHighlights = await GetKeywordHighlightsAsync(document, text, position, cancellationToken).ConfigureAwait(false); + if (keywordHighlights.Any()) + { + return keywordHighlights.ToArray(); + } + + // Not a keyword, check if it is a reference that needs highlighting. + var referenceHighlights = await GetReferenceHighlightsAsync(document, text, position, cancellationToken).ConfigureAwait(false); + if (referenceHighlights.Any()) + { + return referenceHighlights.ToArray(); + } + + // No keyword or references to highlight at this location. + return Array.Empty(); + } + + private async Task> GetKeywordHighlightsAsync(Document document, SourceText text, int position, CancellationToken cancellationToken) + { + var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + + var keywordSpans = new List(); + _highlightingService.AddHighlights(root, position, keywordSpans, cancellationToken); + + return keywordSpans.SelectAsArray(highlight => new DocumentHighlight + { + Kind = DocumentHighlightKind.Text, + Range = ProtocolConversions.TextSpanToRange(highlight, text) + }); + } + + private static async Task> GetReferenceHighlightsAsync(Document document, SourceText text, int position, CancellationToken cancellationToken) + { + var documentHighlightService = document.GetRequiredLanguageService(); + var options = DocumentHighlightingOptions.From(document.Project); var highlights = await documentHighlightService.GetDocumentHighlightsAsync( document, position, @@ -53,16 +95,15 @@ public DocumentHighlightsHandler() { // LSP requests are only for a single document. So just get the highlights for the requested document. var highlightsForDocument = highlights.FirstOrDefault(h => h.Document.Id == document.Id); - var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); - return highlightsForDocument.HighlightSpans.Select(h => new DocumentHighlight + return highlightsForDocument.HighlightSpans.SelectAsArray(h => new DocumentHighlight { Range = ProtocolConversions.TextSpanToRange(h.TextSpan, text), Kind = ProtocolConversions.HighlightSpanKindToDocumentHighlightKind(h.Kind), - }).ToArray(); + }); } - return Array.Empty(); + return ImmutableArray.Empty; } } } diff --git a/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.ParsedXmlSnippet.cs b/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.ParsedXmlSnippet.cs new file mode 100644 index 0000000000000..01807f1e44089 --- /dev/null +++ b/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.ParsedXmlSnippet.cs @@ -0,0 +1,87 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.LanguageServer.Handler.InlineCompletions; + +internal partial class InlineCompletionsHandler +{ + private class ParsedXmlSnippet + { + public ImmutableArray Parts { get; } + public string DefaultText { get; } + + public ParsedXmlSnippet(ImmutableArray parts) + { + Parts = parts; + + using var _ = PooledStringBuilder.GetInstance(out var defaultSnippetBuilder); + foreach (var part in parts) + { + var textToAdd = part.DefaultText; + defaultSnippetBuilder.Append(textToAdd); + } + + DefaultText = defaultSnippetBuilder.ToString(); + } + } + + private abstract record SnippetPart(string DefaultText); + + private record SnippetFieldPart(string FieldName, string DefaultText, int? EditIndex) : SnippetPart(DefaultText); + + private record SnippetFunctionPart(string FieldName, string DefaultText, int? EditIndex, string FunctionName, string? FunctionParam) + : SnippetFieldPart(FieldName, DefaultText, EditIndex) + { + public async Task WithSnippetFunctionResultAsync(Document documentWithSnippet, TextSpan fieldSpan, CancellationToken cancellationToken) + { + var snippetFunctionService = documentWithSnippet.Project.GetRequiredLanguageService(); + switch (FunctionName) + { + case "SimpleTypeName": + if (FunctionParam == null) + { + return this; + } + + var simplifiedTypeName = await SnippetFunctionService.GetSimplifiedTypeNameAsync(documentWithSnippet, fieldSpan, FunctionParam, cancellationToken).ConfigureAwait(false); + if (simplifiedTypeName == null) + { + return this; + } + + return this with { DefaultText = simplifiedTypeName }; + case "ClassName": + var className = await snippetFunctionService.GetContainingClassNameAsync(documentWithSnippet, fieldSpan.Start, cancellationToken).ConfigureAwait(false); + if (className == null) + { + return this; + } + + return this with { DefaultText = className }; + case "GenerateSwitchCases": + // Generate switch cases requires a multi-step snippet interaction, where the snippet is inserted first then the + // client calls back to on commit so that we can generate the cases for the specified switch value. + // This is not yet supported via LSP. + return this; + default: + return this; + } + } + } + + /// + /// To indicate cursor location we put in a multi-line comment so that we can + /// find it after formatting. + /// + private record SnippetCursorPart() : SnippetPart("/*$0*/"); + + private record SnippetStringPart(string Text) : SnippetPart(Text); +} diff --git a/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.XmlSnippetParsing.cs b/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.XmlSnippetParsing.cs new file mode 100644 index 0000000000000..7f26a5fa10f03 --- /dev/null +++ b/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.XmlSnippetParsing.cs @@ -0,0 +1,320 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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.Linq; +using System.Text.RegularExpressions; +using System.Xml; +using System.Xml.Linq; +using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.LanguageServer.Handler.InlineCompletions; + +internal partial class InlineCompletionsHandler +{ + /// + /// Shamelessly copied from the editor + /// https://devdiv.visualstudio.com/DevDiv/_git/VS-Platform?path=/src/Editor/VisualStudio/Impl/Snippet/CodeSnippet.cs + /// + internal class CodeSnippet + { + private const string ExpansionSnippetType = "Expansion"; + + private readonly string[]? _snippetTypes; + + /// + /// Ctor. + /// + /// XElement representing the CodeSnippet node. + public CodeSnippet(XElement codeSnippetElement) + { + var header = GetElementWithoutNamespace(codeSnippetElement, "Header"); + if (header == null) + { + throw new InvalidOperationException("snippet element is missing header."); + } + + CodeSnippetElement = codeSnippetElement; + + Title = GetElementInnerText(header, "Title"); + Shortcut = GetElementInnerText(header, "Shortcut"); + var snippetTypes = GetElementsWithoutNamespace(header, "SnippetTypes"); + if (snippetTypes != null) + { + _snippetTypes = snippetTypes.Elements().Select(e => e.Value.Trim()).ToArray(); + } + } + + public string Title { get; } + + public string Shortcut { get; } + + public XElement CodeSnippetElement { get; } + + public bool IsExpansionSnippet() + { + return _snippetTypes?.Contains(ExpansionSnippetType, StringComparer.OrdinalIgnoreCase) == true; + } + + public static CodeSnippet? ReadSnippetFromFile(string filePath, string snippetTitle, RequestContext context) + { + try + { + context.TraceInformation($"Reading XML from {filePath} for snippet {snippetTitle}"); + var document = XDocument.Load(filePath); + var snippets = ReadSnippets(document); + if (snippets == null) + { + context.TraceError($"Did not find any code snippets in XML"); + return null; + } + + var matchingSnippet = snippets.Value.Single(s => string.Equals(s.Title, snippetTitle, StringComparison.OrdinalIgnoreCase)); + return matchingSnippet; + } + catch (Exception ex) when (FatalError.ReportAndCatch(ex, ErrorSeverity.General)) + { + context.TraceError($"Got exception reading snippet XML from {filePath} for {snippetTitle}"); + context.TraceException(ex); + return null; + } + } + + private static ImmutableArray? ReadCodeSnippetElements(XDocument document) + { + var codeSnippetsElement = document.Root; + if (codeSnippetsElement.Name.LocalName.Equals("CodeSnippets", StringComparison.OrdinalIgnoreCase)) + { + return codeSnippetsElement.Elements().Where(e => e.Name.LocalName.Equals("CodeSnippet", StringComparison.OrdinalIgnoreCase)).ToImmutableArray(); + } + else if (codeSnippetsElement.Name.LocalName.Equals("CodeSnippet", StringComparison.OrdinalIgnoreCase)) + { + return ImmutableArray.Create(codeSnippetsElement); + } + + return null; + } + + public static IEnumerable GetElementsWithoutNamespace(XElement element, string localName) + { + return element.Elements().Where(e => e.Name.LocalName.Equals(localName, StringComparison.OrdinalIgnoreCase)); + } + + public static XElement? GetElementWithoutNamespace(XElement? element, string localName) + { + return element?.Elements().FirstOrDefault(e => e.Name.LocalName.Equals(localName, StringComparison.OrdinalIgnoreCase)); + } + + public static string GetElementInnerText(XElement element, string subElementName) + { + var subElement = GetElementWithoutNamespace(element, subElementName); + return subElement == null ? string.Empty : subElement.Value.Trim(); + } + + /// + /// Visible for testing. + /// + internal static ImmutableArray? ReadSnippets(XDocument document) + { + return ReadCodeSnippetElements(document)?.Select(element => new CodeSnippet(element)).ToImmutableArray(); + } + } + + /// + /// Shamelessly adapted from https://devdiv.visualstudio.com/DevDiv/_git/VS-Platform?path=/src/Editor/VisualStudio/Impl/Snippet/ExpansionTemplate.cs + /// with changes to parsing to store the snippet as a set of parts instead of a single string. + /// + private class ExpansionTemplate + { + private record ExpansionField(string ID, string Default, string? FunctionName, string? FunctionParam, bool IsEditable); + + private const string Selected = "selected"; + private const string End = "end"; + + private readonly List _tokens = new(); + + private readonly string? _code; + private readonly string _delimiter = "$"; + + private readonly CodeSnippet _snippet; + + public ExpansionTemplate(CodeSnippet snippet) + { + _snippet = snippet; + var snippetElement = CodeSnippet.GetElementWithoutNamespace(snippet.CodeSnippetElement, "Snippet"); + var declarationsElement = CodeSnippet.GetElementWithoutNamespace(snippetElement, "Declarations"); + ReadDeclarations(declarationsElement); + var code = CodeSnippet.GetElementWithoutNamespace(snippetElement, "Code"); + if (code == null) + { + throw new InvalidOperationException("snippet is missing code element."); + } + + _code = Regex.Replace(code.Value, "(? a.Name.LocalName.Equals("Delimiter", StringComparison.OrdinalIgnoreCase)); + if (delimiterAttribute != null) + { + _delimiter = delimiterAttribute.Value; + } + } + + private void ReadDeclarations(XElement? declarations) + { + if (declarations == null) + { + return; + } + + foreach (var declarationElement in declarations.Elements()) + { + var editableAttribute = declarationElement.Attribute("Editable"); + var functionElement = CodeSnippet.GetElementWithoutNamespace(declarationElement, "Function"); + SnippetFunctionService.TryGetSnippetFunctionInfo(functionElement?.Value, out var functionName, out var functionParam); + _tokens.Add(new ExpansionField( + CodeSnippet.GetElementInnerText(declarationElement, "ID"), + CodeSnippet.GetElementInnerText(declarationElement, "Default") ?? " ", + functionName, + functionParam, + editableAttribute == null || string.Equals(editableAttribute.Value, "true", StringComparison.Ordinal) || string.Equals(editableAttribute.Value, "1", StringComparison.Ordinal))); + } + } + + public ParsedXmlSnippet? Parse(RequestContext context) + { + try + { + return Parse(); + } + catch (Exception ex) when (FatalError.ReportAndCatch(ex, ErrorSeverity.General)) + { + context.TraceInformation($"Got exception parsing snippet code for {_snippet.Title}"); + context.TraceException(ex); + return null; + } + } + + private ParsedXmlSnippet? Parse() + { + int iTokenLen; + var currentCharIndex = 0; + var currentTokenCharIndex = 0; + var sps = SnippetParseState.Code; + + // Associate the field id to the index of the field in the snippet. + var fieldNameToSnippetIndex = new Dictionary(); + var currentTabStopIndex = 1; + + using var builder = ArrayBuilder.GetInstance(out var snippetParts); + + // Mechanically ported from env/msenv/textmgr/ExpansionTemplate.cpp + while (currentCharIndex < _code!.Length) + { + iTokenLen = currentCharIndex - currentTokenCharIndex; + + switch (sps) + { + case SnippetParseState.Code: + if (string.Equals(_code[currentCharIndex].ToString(CultureInfo.CurrentCulture), _delimiter, StringComparison.Ordinal)) + { + // we just hit a $, denoting a literal + sps = SnippetParseState.Literal; + + // copy anything from the previous token into our string + if (currentCharIndex > currentTokenCharIndex) + { + // append the token into our buffer + var token = _code.Substring(currentTokenCharIndex, iTokenLen); + snippetParts.Add(new SnippetStringPart(token)); + } + + // start the new token at the next character + currentTokenCharIndex = currentCharIndex; + currentTokenCharIndex++; + } + + break; + + case SnippetParseState.Literal: + if (string.Equals(_code[currentCharIndex].ToString(CultureInfo.CurrentCulture), _delimiter, StringComparison.Ordinal)) + { + // we just hit the $, ending the literal + sps = SnippetParseState.Code; + + // if we have any token, it's a literal, otherwise it's an escaped '$' + if (iTokenLen > 0) + { + // allocate a buffer and get the string name of this literal + var fieldNameLength = currentCharIndex - currentTokenCharIndex; + + var fieldName = _code.Substring(currentTokenCharIndex, fieldNameLength); + + // first check to see if this is a "special" literal + if (string.Equals(fieldName, Selected, StringComparison.Ordinal)) + { + // LSP client currently only invokes on typing (tab) so there is no way to have a selection as part of a snippet request. + // Additionally, TM_SELECTED_TEXT is not supported in the VS LSP client, so we can't set the selection even if we wanted to. + // Since there's no way for the user to ask for a selection replacement, we can ignore it. + } + else if (string.Equals(fieldName, End, StringComparison.Ordinal)) + { + snippetParts.Add(new SnippetCursorPart()); + } + else + { + var field = FindField(fieldName); + if (field != null) + { + // If we have an editable field we need to know its order in the snippet so we can place the appropriate tab stop indices. + int? fieldIndex = field.IsEditable ? fieldNameToSnippetIndex.GetOrAdd(field.ID, (key) => currentTabStopIndex++) : null; + var fieldPart = string.IsNullOrEmpty(field.FunctionName) + ? new SnippetFieldPart(field.ID, field.Default, fieldIndex) + : new SnippetFunctionPart(field.ID, field.Default, fieldIndex, field.FunctionName, field.FunctionParam); + snippetParts.Add(fieldPart); + } + } + } + else + { + // simply append a '$' + snippetParts.Add(new SnippetStringPart(_delimiter)); + } + + // start the new token at the next character + currentTokenCharIndex = currentCharIndex; + currentTokenCharIndex++; + } + + break; + } + + currentCharIndex++; + } + + // do we have any remaining text to be copied? + if (sps == SnippetParseState.Code && (currentCharIndex > currentTokenCharIndex)) + { + var remaining = _code.Substring(currentTokenCharIndex, currentCharIndex - currentTokenCharIndex); + snippetParts.Add(new SnippetStringPart(remaining)); + } + + return snippetParts.Any() ? new ParsedXmlSnippet(snippetParts.ToImmutable()) : null; + } + + private ExpansionField FindField(string fieldName) + { + return _tokens.FirstOrDefault(t => string.Equals(t.ID, fieldName, StringComparison.Ordinal)); + } + + private enum SnippetParseState + { + Code, + Literal + } + } +} diff --git a/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.cs b/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.cs new file mode 100644 index 0000000000000..9f962a4eda6ab --- /dev/null +++ b/src/Features/LanguageServer/Protocol/Handler/InlineCompletions/InlineCompletionsHandler.cs @@ -0,0 +1,289 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Composition; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Collections; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Snippets; +using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.LanguageServer.Protocol; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.LanguageServer.Handler.InlineCompletions; + +/// +/// Supports built in legacy snippets for razor scenarios. +/// +[ExportRoslynLanguagesLspRequestHandlerProvider, Shared] +[ProvidesMethod(VSInternalMethods.TextDocumentInlineCompletionName)] +internal partial class InlineCompletionsHandler : AbstractStatelessRequestHandler +{ + /// + /// The set of built in snippets from, typically found in + /// C:\Program Files\Microsoft Visual Studio\2022\VS_INSTANCE\VC#\Snippets\1033\Visual C# + /// These are currently the only snippets supported. + /// + public static ImmutableHashSet BuiltInSnippets = ImmutableHashSet.Create( + "~", "Attribute", "checked", "class", "ctor", "cw", "do", "else", "enum", "equals", "Exception", "for", "foreach", "forr", + "if", "indexer", "interface", "invoke", "iterator", "iterindex", "lock", "mbox", "namespace", "#if", "#region", "prop", + "propfull", "propg", "sim", "struct", "svm", "switch", "try", "tryf", "unchecked", "unsafe", "using", "while"); + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public InlineCompletionsHandler() + { + } + + public override string Method => VSInternalMethods.TextDocumentInlineCompletionName; + + public override bool MutatesSolutionState => false; + + public override bool RequiresLSPSolution => true; + + public override TextDocumentIdentifier? GetTextDocumentIdentifier(VSInternalInlineCompletionRequest request) + { + return request.TextDocument; + } + + public override async Task HandleRequestAsync(VSInternalInlineCompletionRequest request, RequestContext context, CancellationToken cancellationToken) + { + Contract.ThrowIfNull(context.Document); + + // First get available snippets if any. + var snippetInfoService = context.Document.Project.GetRequiredLanguageService(); + var snippetInfo = snippetInfoService.GetSnippetsIfAvailable(); + if (!snippetInfo.Any()) + { + return null; + } + + // Then attempt to get the word at the requested position. + var sourceText = await context.Document.GetTextAsync(cancellationToken).ConfigureAwait(false); + var syntaxFactsService = context.Document.Project.GetRequiredLanguageService(); + var linePosition = ProtocolConversions.PositionToLinePosition(request.Position); + var position = sourceText.Lines.GetPosition(linePosition); + if (!SnippetUtilities.TryGetWordOnLeft(position, sourceText, syntaxFactsService, out var wordOnLeft)) + { + return null; + } + + // Find the snippet with shortcut text that matches the typed word. + var wordText = sourceText.GetSubText(wordOnLeft.Value).ToString(); + if (!BuiltInSnippets.Contains(wordText, StringComparer.OrdinalIgnoreCase)) + { + return null; + } + + var matchingSnippetInfo = snippetInfo.First(s => wordText.Equals(s.Shortcut, StringComparison.OrdinalIgnoreCase)); + + var matchingSnippet = RetrieveSnippetFromXml(matchingSnippetInfo, context); + if (matchingSnippet == null) + { + return null; + } + + // We currently only support snippet expansions, the others require selection support which is not applicable here. + if (!matchingSnippet.IsExpansionSnippet()) + { + return null; + } + + var expansion = new ExpansionTemplate(matchingSnippet); + + // Parse the snippet XML + var parsedSnippet = expansion.Parse(context); + if (parsedSnippet == null) + { + context.TraceError($"Could not parse code from snippet {matchingSnippet.Title}"); + return null; + } + + var formattedLspSnippet = await GetFormattedLspSnippetAsync(parsedSnippet, wordOnLeft.Value, context.Document, sourceText, cancellationToken).ConfigureAwait(false); + + return new VSInternalInlineCompletionList + { + Items = new VSInternalInlineCompletionItem[] + { + new VSInternalInlineCompletionItem + { + Range = ProtocolConversions.TextSpanToRange(wordOnLeft.Value, sourceText), + Text = formattedLspSnippet, + TextFormat = InsertTextFormat.Snippet, + } + } + }; + } + + /// + /// Formats the snippet by applying the snippet to the document with the default values / function results for snippet declarations. + /// Then converts back into an LSP snippet by replacing the declarations with the appropriate LSP tab stops. + /// + /// Note that the operations in this method are sensitive to the context in the document and so must be calculated on each request. + /// + private static async Task GetFormattedLspSnippetAsync(ParsedXmlSnippet parsedSnippet, TextSpan snippetShortcut, Document originalDocument, SourceText originalSourceText, CancellationToken cancellationToken) + { + // Calculate the snippet text with defaults + snippet function results. + var (snippetFullText, fields, caretSpan) = await GetReplacedSnippetTextAsync( + originalDocument, originalSourceText, snippetShortcut, parsedSnippet, cancellationToken).ConfigureAwait(false); + + // Create a document with the default snippet text that we can use to format the snippet. + var textChange = new TextChange(snippetShortcut, snippetFullText); + var snippetEndPosition = textChange.Span.Start + textChange.NewText!.Length; + + var documentWithSnippetText = originalSourceText.WithChanges(textChange); + var root = await originalDocument.WithText(documentWithSnippetText).GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + + var spanToFormat = TextSpan.FromBounds(textChange.Span.Start, snippetEndPosition); + var formattingChanges = Formatter.GetFormattedTextChanges(root, spanToFormat, originalDocument.Project.Solution.Workspace, cancellationToken: cancellationToken) + ?.ToImmutableArray() ?? ImmutableArray.Empty; + + var formattedText = documentWithSnippetText.WithChanges(formattingChanges); + + // We now have a formatted snippet with default values. We need to + // replace the fields and caret with the proper LSP tab stop notation. + // Since formatting changes are entirely whitespace, we can calculate the new locations by + // adjusting the old spans based on the formatting changes that occured before them. + + // Get the adjusted snippet bounds. + snippetEndPosition = GetAdjustedSpan(formattingChanges, new TextSpan(snippetEndPosition, 0)).Start; + var spanContainingFormattedSnippet = TextSpan.FromBounds(snippetShortcut.Start, snippetEndPosition); + + // Get the adjusted fields and determine the text edits to make LSP formatted tab stops. + using var _1 = ArrayBuilder.GetInstance(out var lspTextChanges); + foreach (var (field, spans) in fields) + { + var lspTextForField = string.IsNullOrEmpty(field.DefaultText) ? $"${{{field.EditIndex}}}" : $"${{{field.EditIndex}:{field.DefaultText}}}"; + foreach (var span in spans) + { + // Adjust the span based on the formatting changes and build the snippet text change. + var fieldInFormattedText = GetAdjustedSpan(formattingChanges, span); + var fieldInSnippetContext = GetTextSpanInContextOfSnippet(fieldInFormattedText.Start, spanContainingFormattedSnippet.Start, fieldInFormattedText.Length); + lspTextChanges.Add(new TextChange(fieldInSnippetContext, lspTextForField)); + } + } + + // Get the adjusted caret location and replace the placeholder comment with the LSP formatted tab stop. + if (caretSpan != null) + { + var caretInFormattedText = GetAdjustedSpan(formattingChanges, caretSpan.Value); + var caretInSnippetContext = GetTextSpanInContextOfSnippet(caretInFormattedText.Start, spanContainingFormattedSnippet.Start, caretInFormattedText.Length); + lspTextChanges.Add(new TextChange(caretInSnippetContext, "$0")); + } + + // Apply all the text changes to get the text formatted as the LSP snippet syntax. + var formattedLspSnippetText = formattedText.GetSubText(spanContainingFormattedSnippet).WithChanges(lspTextChanges); + + return formattedLspSnippetText.ToString(); + + static TextSpan GetAdjustedSpan(ImmutableArray textChanges, TextSpan originalSpan) + { + var textChangesBefore = textChanges.Where(t => t.Span.End <= originalSpan.Start); + var amountToAdjust = textChangesBefore.Sum(t => t.NewText!.Length - t.Span.Length); + return new TextSpan(originalSpan.Start + amountToAdjust, originalSpan.Length); + } + + static TextSpan GetTextSpanInContextOfSnippet(int positionInFullText, int snippetPositionInFullText, int length) + { + var offsetInSnippet = new TextSpan(positionInFullText - snippetPositionInFullText, length); + return offsetInSnippet; + } + } + + /// + /// Create the snippet with the full default text and functions applied. Output the spans associated with + /// each field and the final caret location in that text so that we can find those locations later. + /// + private static async Task<(string ReplacedSnippetText, ImmutableDictionary> Fields, TextSpan? CaretSpan)> GetReplacedSnippetTextAsync( + Document originalDocument, + SourceText originalSourceText, + TextSpan snippetSpan, + ParsedXmlSnippet parsedSnippet, + CancellationToken cancellationToken) + { + var documentWithDefaultSnippet = originalDocument.WithText( + originalSourceText.WithChanges(new TextChange(snippetSpan, parsedSnippet.DefaultText))); + + // Iterate the snippet parts so that we can do two things: + // 1. Calculate the snippet function result. This must be done against the document containing the default snippet text + // as the function result is context dependent. + // 2. After inserting the function result, determine the spans associated with each editable snippet field. + var fieldOffsets = new Dictionary>(); + using var _ = PooledStringBuilder.GetInstance(out var functionSnippetBuilder); + TextSpan? caretSpan = null; + + // This represents the field start location in the context of the snippet without functions replaced (see below). + var locationInDefaultSnippet = snippetSpan.Start; + + // This represents the field start location in the context of the snippet with functions replaced. + var locationInFinalSnippet = snippetSpan.Start; + foreach (var originalPart in parsedSnippet.Parts) + { + var part = originalPart; + + // Adjust the text associated with this snippet part by applying the result of the snippet function. + if (part is SnippetFunctionPart functionPart) + { + // To avoid a bunch of document changes and re-parsing, we always calculate the snippet function result + // against the document with the default snippet text applied to it instead of with each incremental function result. + // So we need to remember the index into the original document. + part = await functionPart.WithSnippetFunctionResultAsync(documentWithDefaultSnippet, new TextSpan(locationInDefaultSnippet, part.DefaultText.Length), cancellationToken).ConfigureAwait(false); + } + + // Only store spans for editable fields or the cursor location, we don't need to get back to anything else. + if (part is SnippetFieldPart fieldPart && fieldPart.EditIndex != null) + { + var fieldSpan = new TextSpan(locationInFinalSnippet, part.DefaultText.Length); + fieldOffsets[fieldPart] = fieldOffsets.GetValueOrDefault(fieldPart, ImmutableArray.Empty).Add(fieldSpan); + } + else if (part is SnippetCursorPart cursorPart) + { + caretSpan = new TextSpan(locationInFinalSnippet, cursorPart.DefaultText.Length); + } + + // Append the new snippet part to the text and track the location of the field in the text w/ functions. + locationInFinalSnippet += part.DefaultText.Length; + functionSnippetBuilder.Append(part.DefaultText); + + // Keep track of the original field location in the text w/out functions. + locationInDefaultSnippet += originalPart.DefaultText.Length; + } + + return (functionSnippetBuilder.ToString(), fieldOffsets.ToImmutableDictionary(), caretSpan); + } + + private static CodeSnippet? RetrieveSnippetFromXml(SnippetInfo snippetInfo, RequestContext context) + { + context.TraceInformation($"Reading XML for {snippetInfo.Title} with path {snippetInfo.Path}"); + + var path = snippetInfo.Path; + if (path == null) + { + context.TraceInformation($"Missing file path for snippet {snippetInfo.Title}"); + return null; + } + + if (!File.Exists(path)) + { + context.TraceInformation($"Snippet {snippetInfo.Title} has an invalid file path: {snippetInfo.Path}"); + return null; + } + + // Load the xml for the snippet from disk. + // Any exceptions thrown here we allow to bubble up and let the queue log it. + var snippet = CodeSnippet.ReadSnippetFromFile(snippetInfo.Path, snippetInfo.Title, context); + return snippet; + } +} diff --git a/src/Features/LanguageServer/Protocol/Handler/OnAutoInsert/OnAutoInsertHandler.cs b/src/Features/LanguageServer/Protocol/Handler/OnAutoInsert/OnAutoInsertHandler.cs index b8bd9a197bc71..c536ad0e84e08 100644 --- a/src/Features/LanguageServer/Protocol/Handler/OnAutoInsert/OnAutoInsertHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/OnAutoInsert/OnAutoInsertHandler.cs @@ -201,7 +201,7 @@ static SourceText GetIndentedText( var amountToIndent = desiredCaretLinePosition.Character - lineToIndent.Span.Length; // Create and apply a text change with whitespace for the indentation amount. - var indentText = amountToIndent.CreateIndentationString(options.FormattingOptions.GetOption(FormattingOptions2.UseTabs), options.FormattingOptions.GetOption(FormattingOptions2.TabSize)); + var indentText = amountToIndent.CreateIndentationString(options.FormattingOptions.UseTabs, options.FormattingOptions.TabSize); var indentedText = textToIndent.WithChanges(new TextChange(new TextSpan(lineToIndent.End, 0), indentText)); return indentedText; } diff --git a/src/Features/LanguageServer/Protocol/Handler/RequestContext.cs b/src/Features/LanguageServer/Protocol/Handler/RequestContext.cs index 424d747c7d6a3..12a03cebb76a5 100644 --- a/src/Features/LanguageServer/Protocol/Handler/RequestContext.cs +++ b/src/Features/LanguageServer/Protocol/Handler/RequestContext.cs @@ -62,11 +62,11 @@ internal readonly struct RequestContext /// /// Tracing object that can be used to log information about the status of requests. /// - private readonly Action _traceInformation; + private readonly ILspLogger _logger; public RequestContext( Solution? solution, - Action traceInformation, + ILspLogger logger, ClientCapabilities clientCapabilities, string? clientName, Document? document, @@ -82,7 +82,7 @@ public RequestContext( SupportedLanguages = supportedLanguages; GlobalOptions = globalOptions; _documentChangeTracker = documentChangeTracker; - _traceInformation = traceInformation; + _logger = logger; _trackedDocuments = trackedDocuments; } @@ -107,7 +107,7 @@ public RequestContext( // so they're not accidentally operating on stale solution state. if (!requiresLSPSolution) { - return new RequestContext(solution: null, logger.TraceInformation, clientCapabilities, clientName, document: null, documentChangeTracker, trackedDocuments, supportedLanguages, globalOptions); + return new RequestContext(solution: null, logger, clientCapabilities, clientName, document: null, documentChangeTracker, trackedDocuments, supportedLanguages, globalOptions); } // Go through each registered workspace, find the solution that contains the document that @@ -133,7 +133,7 @@ public RequestContext( var context = new RequestContext( workspaceSolution, - logger.TraceInformation, + logger, clientCapabilities, clientName, document, @@ -178,6 +178,15 @@ public bool IsTracking(Uri documentUri) /// Logs an informational message. /// public void TraceInformation(string message) - => _traceInformation(message); + => _logger.TraceInformation(message); + + public void TraceWarning(string message) + => _logger.TraceWarning(message); + + public void TraceError(string message) + => _logger.TraceError(message); + + public void TraceException(Exception exception) + => _logger.TraceException(exception); } } diff --git a/src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs b/src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs index 181b902e53b7d..02c373d8b5aba 100644 --- a/src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs +++ b/src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs @@ -54,7 +54,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler /// internal partial class RequestExecutionQueue { - private readonly string _serverName; + private readonly WellKnownLspServerKinds _serverKind; private readonly ImmutableArray _supportedLanguages; /// @@ -93,19 +93,18 @@ public RequestExecutionQueue( LspMiscellaneousFilesWorkspace? lspMiscellaneousFilesWorkspace, IGlobalOptionService globalOptions, ImmutableArray supportedLanguages, - string serverName, - string serverTypeName) + WellKnownLspServerKinds serverKind) { _logger = logger; _globalOptions = globalOptions; _supportedLanguages = supportedLanguages; - _serverName = serverName; + _serverKind = serverKind; // Pass the language client instance type name to the telemetry logger to ensure we can // differentiate between the different C# LSP servers that have the same client name. // We also don't use the language client's name property as it is a localized user facing string // which is difficult to write telemetry queries for. - _requestTelemetryLogger = new RequestTelemetryLogger(serverTypeName); + _requestTelemetryLogger = new RequestTelemetryLogger(_serverKind.ToTelemetryString()); _lspWorkspaceManager = new LspWorkspaceManager(logger, lspMiscellaneousFilesWorkspace, lspWorkspaceRegistrationService, _requestTelemetryLogger); @@ -188,7 +187,7 @@ public void Shutdown() // The queue itself is threadsafe (_queue.TryEnqueue and _queue.Complete use the same lock). if (!didEnqueue) { - return Task.FromException(new InvalidOperationException($"{_serverName} was requested to shut down.")); + return Task.FromException(new InvalidOperationException($"{_serverKind.ToUserVisibleString()} was requested to shut down.")); } return resultTask; @@ -255,7 +254,7 @@ private async Task ProcessQueueAsync() // We encountered an unexpected exception in processing the queue or in a mutating request. // Log it, shutdown the queue, and exit the loop. _logger.TraceException(ex); - OnRequestServerShutdown($"Error occurred processing queue in {_serverName}: {ex.Message}."); + OnRequestServerShutdown($"Error occurred processing queue in {_serverKind.ToUserVisibleString()}: {ex.Message}."); return; } } diff --git a/src/Features/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs b/src/Features/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs index 9700fe8e8003c..e11f9612b3cd1 100644 --- a/src/Features/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/SignatureHelp/SignatureHelpHandler.cs @@ -12,8 +12,8 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.SignatureHelp; +using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Text.Adornments; -using Roslyn.Utilities; using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.Handler @@ -23,19 +23,23 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler internal class SignatureHelpHandler : AbstractStatelessRequestHandler { private readonly IEnumerable> _allProviders; - - public override string Method => LSP.Methods.TextDocumentSignatureHelpName; - - public override bool MutatesSolutionState => false; - public override bool RequiresLSPSolution => true; + private readonly IGlobalOptionService _globalOptions; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public SignatureHelpHandler([ImportMany] IEnumerable> allProviders) + public SignatureHelpHandler( + [ImportMany] IEnumerable> allProviders, + IGlobalOptionService globalOptions) { _allProviders = allProviders; + _globalOptions = globalOptions; } + public override string Method => LSP.Methods.TextDocumentSignatureHelpName; + + public override bool MutatesSolutionState => false; + public override bool RequiresLSPSolution => true; + public override LSP.TextDocumentIdentifier? GetTextDocumentIdentifier(LSP.TextDocumentPositionParams request) => request.TextDocument; public override async Task HandleRequestAsync(LSP.TextDocumentPositionParams request, RequestContext context, CancellationToken cancellationToken) @@ -48,7 +52,7 @@ public SignatureHelpHandler([ImportMany] IEnumerable p.Metadata.Language == document.Project.Language); var triggerInfo = new SignatureHelpTriggerInfo(SignatureHelpTriggerReason.InvokeSignatureHelpCommand); - var options = SignatureHelpOptions.From(document.Project); + var options = _globalOptions.GetSignatureHelpOptions(document.Project.Language); foreach (var provider in providers) { diff --git a/src/Features/LanguageServer/Protocol/LanguageServerTarget.cs b/src/Features/LanguageServer/Protocol/LanguageServerTarget.cs index 5474aa81f5c35..da4a8a891fcbe 100644 --- a/src/Features/LanguageServer/Protocol/LanguageServerTarget.cs +++ b/src/Features/LanguageServer/Protocol/LanguageServerTarget.cs @@ -32,16 +32,6 @@ internal class LanguageServerTarget : ILanguageServerTarget protected readonly ILspLogger Logger; protected readonly string? ClientName; - /// - /// Server name used when sending error messages to the client. - /// - private readonly string _userVisibleServerName; - - /// - /// Server name used when capturing error telemetry. - /// - protected readonly string TelemetryServerName; - // Set on first LSP initialize request. protected ClientCapabilities? _clientCapabilities; @@ -62,11 +52,10 @@ internal LanguageServerTarget( ILspLogger logger, ImmutableArray supportedLanguages, string? clientName, - string userVisibleServerName, - string telemetryServerTypeName) + WellKnownLspServerKinds serverKind) { GlobalOptions = globalOptions; - RequestDispatcher = requestDispatcherFactory.CreateRequestDispatcher(supportedLanguages); + RequestDispatcher = requestDispatcherFactory.CreateRequestDispatcher(supportedLanguages, serverKind); _capabilitiesProvider = capabilitiesProvider; WorkspaceRegistrationService = workspaceRegistrationService; @@ -79,17 +68,13 @@ internal LanguageServerTarget( Listener = listenerProvider.GetListener(FeatureAttribute.LanguageServer); ClientName = clientName; - _userVisibleServerName = userVisibleServerName; - TelemetryServerName = telemetryServerTypeName; - Queue = new RequestExecutionQueue( logger, workspaceRegistrationService, lspMiscellaneousFilesWorkspace, globalOptions, supportedLanguages, - userVisibleServerName, - TelemetryServerName); + serverKind); Queue.RequestServerShutdown += RequestExecutionQueue_Errored; } @@ -140,7 +125,7 @@ public Task ShutdownAsync(CancellationToken _) } } - protected virtual void ShutdownImpl() + protected void ShutdownImpl() { Contract.ThrowIfTrue(_shuttingDown, "Shutdown has already been called."); diff --git a/src/Features/LanguageServer/Protocol/RequestDispatcher.cs b/src/Features/LanguageServer/Protocol/RequestDispatcher.cs index de7f64b8c1d7b..7a0f6047c2155 100644 --- a/src/Features/LanguageServer/Protocol/RequestDispatcher.cs +++ b/src/Features/LanguageServer/Protocol/RequestDispatcher.cs @@ -24,12 +24,17 @@ internal class RequestDispatcher { private readonly ImmutableDictionary> _requestHandlers; - public RequestDispatcher(ImmutableArray> requestHandlerProviders, ImmutableArray languageNames) + public RequestDispatcher( + ImmutableArray> requestHandlerProviders, + ImmutableArray languageNames, + WellKnownLspServerKinds serverKind) { - _requestHandlers = CreateMethodToHandlerMap(requestHandlerProviders.Where(rh => languageNames.All(languageName => rh.Metadata.LanguageNames.Contains(languageName)))); + _requestHandlers = CreateMethodToHandlerMap(requestHandlerProviders.Where(rh => languageNames.All(languageName => rh.Metadata.LanguageNames.Contains(languageName))), serverKind); } - private static ImmutableDictionary> CreateMethodToHandlerMap(IEnumerable> requestHandlerProviders) + private static ImmutableDictionary> CreateMethodToHandlerMap( + IEnumerable> requestHandlerProviders, + WellKnownLspServerKinds serverKind) { var requestHandlerDictionary = ImmutableDictionary.CreateBuilder>(StringComparer.OrdinalIgnoreCase); @@ -41,7 +46,7 @@ private static ImmutableDictionary> CreateMethodTo // This ensures 2 things: // 1. That the handler provider is not instantiated (and therefore its dependencies are not) until a handler it provides is needed. // 2. That the handler provider's CreateRequestHandlers is only called once and always returns the same handler instances. - var lazyProviders = new Lazy>(() => handlerProvider.Value.CreateRequestHandlers().ToImmutableDictionary(p => p.Method, p => p, StringComparer.OrdinalIgnoreCase)); + var lazyProviders = new Lazy>(() => handlerProvider.Value.CreateRequestHandlers(serverKind).ToImmutableDictionary(p => p.Method, p => p, StringComparer.OrdinalIgnoreCase)); foreach (var method in methods) { diff --git a/src/Features/LanguageServer/Protocol/WellKnownLspServerKinds.cs b/src/Features/LanguageServer/Protocol/WellKnownLspServerKinds.cs new file mode 100644 index 0000000000000..cc1f53e33fff5 --- /dev/null +++ b/src/Features/LanguageServer/Protocol/WellKnownLspServerKinds.cs @@ -0,0 +1,83 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.LanguageServer; + +internal enum WellKnownLspServerKinds +{ + /// + /// Roslyn LSP server for razor c# requests. + /// + RazorLspServer, + + /// + /// Roslyn LSP server for liveshare guests. + /// + LiveShareLspServer, + + /// + /// Roslyn LSP server always activated in VS. + /// + AlwaysActiveVSLspServer, + + /// + /// Roslyn LSP server for non-VS use cases. + /// + CSharpVisualBasicLspServer, + + /// + /// XAML LSP servers. + /// + XamlLspServer, + XamlLspServerDisableUX, +} + +internal static class WellKnownLspServerExtensions +{ + public static string ToUserVisibleString(this WellKnownLspServerKinds server) + { + return server switch + { + WellKnownLspServerKinds.RazorLspServer => "Razor C# Language Server Client", + WellKnownLspServerKinds.LiveShareLspServer => "Live Share C#/Visual Basic Language Server Client", + WellKnownLspServerKinds.AlwaysActiveVSLspServer => "Roslyn Language Server Client", + WellKnownLspServerKinds.CSharpVisualBasicLspServer => "Roslyn Language Server Client", + + // When updating the string of Name, please make sure to update the same string in Microsoft.VisualStudio.LanguageServer.Client.ExperimentalSnippetSupport.AllowList + WellKnownLspServerKinds.XamlLspServer => "XAML Language Server Client (Experimental)", + WellKnownLspServerKinds.XamlLspServerDisableUX => "XAML Language Server Client for LiveShare and Codespaces", + _ => throw ExceptionUtilities.UnexpectedValue(server), + }; + } + + public static string ToTelemetryString(this WellKnownLspServerKinds server) + { + return server switch + { + // Telemetry was previously reported as RazorInProcLanguageClient.GetType().Name + WellKnownLspServerKinds.RazorLspServer => "RazorInProcLanguageClient", + + // Telemtry was previously reported as LiveShareInProcLanguageClient.GetType().Name + WellKnownLspServerKinds.LiveShareLspServer => "LiveShareInProcLanguageClient", + + // Telemtry was previously reported as AlwaysActivateInProcLanguageClient.GetType().Name + WellKnownLspServerKinds.AlwaysActiveVSLspServer => "AlwaysActivateInProcLanguageClient", + + // Telemetry was previously reported as CSharpVisualBasicLanguageServerFactory.GetType().Name + WellKnownLspServerKinds.CSharpVisualBasicLspServer => "CSharpVisualBasicLanguageServerFactory", + + // Telemetry was previously reported as XamlInProcLanguageClient.GetType().Name + WellKnownLspServerKinds.XamlLspServer => "XamlInProcLanguageClient", + + // Telemetry was previously reported as XamlInProcLanguageClientDisableUX.GetType().Name + WellKnownLspServerKinds.XamlLspServerDisableUX => "XamlInProcLanguageClientDisableUX", + _ => throw ExceptionUtilities.UnexpectedValue(server), + }; + } +} diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Completion/CompletionResolveTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/Completion/CompletionResolveTests.cs index 5b7df30d20390..ca05efafd8712 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Completion/CompletionResolveTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Completion/CompletionResolveTests.cs @@ -460,7 +460,7 @@ public override Task GetChangeAsync( return Task.FromResult(CompletionChange.Create(textChange, newPosition: 0)); } - internal override bool ShouldTriggerCompletion(Project project, HostLanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CodeAnalysis.Completion.CompletionOptions options, ImmutableHashSet roles = null) + internal override bool ShouldTriggerCompletion(Project project, HostLanguageServices languageServices, SourceText text, int caretPosition, CompletionTrigger trigger, CodeAnalysis.Completion.CompletionOptions options, OptionSet passthroughOptions, ImmutableHashSet roles = null) => false; internal override CompletionRules GetRules(CodeAnalysis.Completion.CompletionOptions options) diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs index e51f2c486f0c5..67bcb053fd123 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs @@ -181,9 +181,7 @@ void M() var solution = testLspServer.TestWorkspace.CurrentSolution; // Make sure the unimported types option is on by default. - testLspServer.TestWorkspace.SetOptions(testLspServer.TestWorkspace.CurrentSolution.Options - .WithChangedOption(CompletionOptions.Metadata.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, true) - .WithChangedOption(CompletionOptions.Metadata.IsExpandedCompletion, true)); + testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(new OptionKey(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp), true); var completionParams = CreateCompletionParams( testLspServer.GetLocations("caret").Single(), @@ -196,7 +194,7 @@ void M() } [Fact] - public async Task TestGetCompletionsDoesNotIncludeSnippetsAsync() + public async Task TestGetCompletionsUsesSnippetOptionAsync() { var markup = @"class A @@ -204,9 +202,9 @@ public async Task TestGetCompletionsDoesNotIncludeSnippetsAsync() {|caret:|} }"; using var testLspServer = await CreateTestLspServerAsync(markup); - var solution = testLspServer.TestWorkspace.CurrentSolution; - solution = solution.WithOptions(solution.Options - .WithChangedOption(CompletionOptions.Metadata.SnippetsBehavior, LanguageNames.CSharp, SnippetsRule.AlwaysInclude)); + + testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption( + new OptionKey(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.CSharp), SnippetsRule.NeverInclude); var completionParams = CreateCompletionParams( testLspServer.GetLocations("caret").Single(), diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs index 0dc05d7138dec..96a6cd95a965f 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs @@ -427,6 +427,54 @@ public class {|caret:|} { } Assert.Equal(originalResultId, results.Single().ResultId); } + [Theory, CombinatorialData] + public async Task TestDocumentDiagnosticsFromRazorServer(bool useVSDiagnostics) + { + var markup = +@"class A {"; + + // Turn off pull diagnostics by default, but send a request to the razor LSP server which is always pull. + using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, BackgroundAnalysisScope.OpenFilesAndProjects, DiagnosticMode.Push, serverKind: WellKnownLspServerKinds.RazorLspServer); + + // Calling GetTextBuffer will effectively open the file. + testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); + + var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); + + await OpenDocumentAsync(testLspServer, document); + + var results = await RunGetDocumentPullDiagnosticsAsync( + testLspServer, document.GetURI(), useVSDiagnostics); + + // Assert that we have diagnostics even though the option is set to push. + Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code); + Assert.NotNull(results.Single().Diagnostics.Single().CodeDescription!.Href); + } + + [Theory, CombinatorialData] + public async Task TestDocumentDiagnosticsFromLiveShareServer(bool useVSDiagnostics) + { + var markup = +@"class A {"; + + // Turn off pull diagnostics by default, but send a request to the razor LSP server which is always pull. + using var testLspServer = await CreateTestWorkspaceWithDiagnosticsAsync(markup, BackgroundAnalysisScope.OpenFilesAndProjects, DiagnosticMode.Push, serverKind: WellKnownLspServerKinds.LiveShareLspServer); + + // Calling GetTextBuffer will effectively open the file. + testLspServer.TestWorkspace.Documents.Single().GetTextBuffer(); + + var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); + + await OpenDocumentAsync(testLspServer, document); + + var results = await RunGetDocumentPullDiagnosticsAsync( + testLspServer, document.GetURI(), useVSDiagnostics); + + // Assert that we have diagnostics even though the option is set to push. + Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code); + Assert.NotNull(results.Single().Diagnostics.Single().CodeDescription!.Href); + } + #endregion #region Workspace Diagnostics @@ -1207,9 +1255,9 @@ private static VSInternalWorkspaceDiagnosticsParams CreateWorkspaceDiagnosticPar private Task CreateTestWorkspaceWithDiagnosticsAsync(string markup, BackgroundAnalysisScope scope, bool pullDiagnostics = true) => CreateTestWorkspaceWithDiagnosticsAsync(markup, scope, pullDiagnostics ? DiagnosticMode.Pull : DiagnosticMode.Push); - private async Task CreateTestWorkspaceWithDiagnosticsAsync(string markup, BackgroundAnalysisScope scope, DiagnosticMode mode) + private async Task CreateTestWorkspaceWithDiagnosticsAsync(string markup, BackgroundAnalysisScope scope, DiagnosticMode mode, WellKnownLspServerKinds serverKind = WellKnownLspServerKinds.AlwaysActiveVSLspServer) { - var testLspServer = await CreateTestLspServerAsync(markup); + var testLspServer = await CreateTestLspServerAsync(markup, serverKind); InitializeDiagnostics(scope, testLspServer.TestWorkspace, mode); return testLspServer; } diff --git a/src/Features/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.LinkedDocuments.cs b/src/Features/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.LinkedDocuments.cs index 6681203f378c0..f6ba6080e5dca 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.LinkedDocuments.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.LinkedDocuments.cs @@ -124,7 +124,7 @@ public GetLspSolutionHandlerProvider() { } - public override ImmutableArray CreateRequestHandlers() => ImmutableArray.Create(new GetLSPSolutionHandler()); + public override ImmutableArray CreateRequestHandlers(WellKnownLspServerKinds serverKind) => ImmutableArray.Create(new GetLSPSolutionHandler()); } private class GetLSPSolutionHandler : IRequestHandler diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Highlights/DocumentHighlightTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/Highlights/DocumentHighlightTests.cs index 7002c84f4b0f2..e0fe7ff9c44a7 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Highlights/DocumentHighlightTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Highlights/DocumentHighlightTests.cs @@ -44,6 +44,33 @@ void M() AssertJsonEquals(expected, results); } + [Fact] + [WorkItem(59120, "https://github.com/dotnet/roslyn/issues/59120")] + public async Task TestGetDocumentHighlightAsync_Keywords() + { + var markup = +@"using System.Threading.Tasks; +class A +{ + {|text:async|} Task MAsync() + { + {|text:await|} Task.Delay(100); + {|caret:|}{|text:await|} Task.Delay(100); + } +}"; + using var testLspServer = await CreateTestLspServerAsync(markup); + + var expectedLocations = testLspServer.GetLocations("text"); + + var results = await RunGetDocumentHighlightAsync(testLspServer, testLspServer.GetLocations("caret").Single()); + + Assert.Equal(3, results.Length); + Assert.All(results, r => Assert.Equal(LSP.DocumentHighlightKind.Text, r.Kind)); + Assert.Equal(expectedLocations[0].Range, results[0].Range); + Assert.Equal(expectedLocations[1].Range, results[1].Range); + Assert.Equal(expectedLocations[2].Range, results[2].Range); + } + [Fact] public async Task TestGetDocumentHighlightAsync_InvalidLocation() { diff --git a/src/Features/LanguageServer/ProtocolUnitTests/InlineCompletions/InlineCompletionsTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/InlineCompletions/InlineCompletionsTests.cs new file mode 100644 index 0000000000000..ab0a5d62b9854 --- /dev/null +++ b/src/Features/LanguageServer/ProtocolUnitTests/InlineCompletions/InlineCompletionsTests.cs @@ -0,0 +1,271 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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.Formatting; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Roslyn.Utilities; +using Xunit; +using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; + +namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests; + +public class InlineCompletionsTests : AbstractLanguageServerProtocolTests +{ + protected override TestComposition Composition => base.Composition.AddParts(typeof(TestSnippetInfoService)); + + [Fact] + public async Task TestSimpleSnippet() + { + var markup = +@"class A +{ + void M() + { + if{|tab:|} + } +}"; + var expectedSnippet = +@"if (${1:true}) + { + $0 + }"; + + await VerifyMarkupAndExpected(markup, expectedSnippet); + } + + [Fact] + public async Task TestSnippetIgnoresCase() + { + var markup = +@"class A +{ + void M() + { + If{|tab:|} + } +}"; + var expectedSnippet = +@"if (${1:true}) + { + $0 + }"; + + await VerifyMarkupAndExpected(markup, expectedSnippet); + } + + [Fact] + public async Task TestSnippetUsesDocumentOptions() + { + var markup = +@"class A +{ + void M() + { + if{|tab:|} + } +}"; + var expectedSnippet = +@"if (${1:true}) + { + $0 + }"; + + await VerifyMarkupAndExpected(markup, expectedSnippet, indentationSize: 1); + } + + [Fact] + public async Task TestSnippetWithMultipleDeclarations() + { + var markup = +@"class A +{ + void M() + { + for{|tab:|} + } +}"; + var expectedSnippet = +@"for (int ${1:i} = 0; ${1:i} < ${2:length}; ${1:i}++) + { + $0 + }"; + + await VerifyMarkupAndExpected(markup, expectedSnippet); + } + + [Fact] + public async Task TestSnippetWithSimpleTypeNameFunctionFullyQualifies() + { + var markup = +@"class A +{ + void M() + { + cw{|tab:|} + } +}"; + var expectedSnippet = @"System.Console.WriteLine($0);"; + + await VerifyMarkupAndExpected(markup, expectedSnippet); + } + + [Fact] + public async Task TestSnippetWithSimpleTypeNameFunctionWithUsing() + { + var markup = +@"using System; +class A +{ + void M() + { + cw{|tab:|} + } +}"; + var expectedSnippet = @"Console.WriteLine($0);"; + + await VerifyMarkupAndExpected(markup, expectedSnippet); + } + + [Fact] + public async Task TestSnippetWithClassNameFunction() + { + var markup = +@"class A +{ + ctor{|tab:|} +}"; + var expectedSnippet = +@"public A() + { + $0 + }"; + + await VerifyMarkupAndExpected(markup, expectedSnippet); + } + + [Fact] + public async Task TestSnippetWithClassNameFunctionOutsideOfClass() + { + var markup = +@"ctor{|tab:|}"; + var expectedSnippet = +@"public ClassNamePlaceholder () +{ + $0 +}"; + + await VerifyMarkupAndExpected(markup, expectedSnippet); + } + + [Fact] + public async Task TestSnippetWithSwitchFunctionOnlyGeneratesDefault() + { + var markup = +@"class A +{ + void M() + { + switch{|tab:|} + } +}"; + var expectedSnippet = +@"switch (${1:switch_on}) + { + default: + }$0"; + + await VerifyMarkupAndExpected(markup, expectedSnippet); + } + + [Fact] + public async Task TestSnippetWithNoEditableFields() + { + var markup = +@"class A +{ + equals{|tab:|} +}"; + var expectedSnippet = +@"// override object.Equals + public override bool Equals(object obj) + { + // + // See the full list of guidelines at + // http://go.microsoft.com/fwlink/?LinkID=85237 + // and also the guidance for operator== at + // http://go.microsoft.com/fwlink/?LinkId=85238 + // + + if (obj == null || GetType() != obj.GetType()) + { + return false; + } + + // TODO: write your implementation of Equals() here + throw new System.NotImplementedException(); + return base.Equals(obj);$0 + } + + // override object.GetHashCode + public override int GetHashCode() + { + // TODO: write your implementation of GetHashCode() here + throw new System.NotImplementedException(); + return base.GetHashCode(); + }"; + + await VerifyMarkupAndExpected(markup, expectedSnippet); + } + + private async Task VerifyMarkupAndExpected(string markup, string expected, int indentationSize = 4) + { + using var testLspServer = await CreateTestLspServerAsync(markup); + var locationTyped = testLspServer.GetLocations("tab").Single(); + + var document = testLspServer.GetCurrentSolution().GetDocuments(locationTyped.Uri).Single(); + var newSolution = document.Project.Solution.WithOptions(testLspServer.TestWorkspace.Options + .WithChangedOption(FormattingOptions.IndentationSize, document.Project.Language, indentationSize)); + testLspServer.TestWorkspace.TryApplyChanges(newSolution); + await WaitForWorkspaceOperationsAsync(testLspServer.TestWorkspace); + + var result = await GetInlineCompletionsAsync(testLspServer, locationTyped); + + AssertEx.NotNull(result); + Assert.Single(result.Items); + + var item = result.Items.Single(); + AssertEx.NotNull(item.Range); + Assert.Equal(LSP.InsertTextFormat.Snippet, item.TextFormat); + Assert.Equal(expected, item.Text); + } + + private static async Task GetInlineCompletionsAsync( + TestLspServer testLspServer, + LSP.Location locationTyped) + { + var request = new LSP.VSInternalInlineCompletionRequest + { + Context = new LSP.VSInternalInlineCompletionContext + { + SelectedCompletionInfo = null, + TriggerKind = LSP.VSInternalInlineCompletionTriggerKind.Explicit + }, + Position = locationTyped.Range.Start, + TextDocument = CreateTextDocumentIdentifier(locationTyped.Uri) + }; + + var response = await testLspServer.ExecuteRequestAsync(LSP.VSInternalMethods.TextDocumentInlineCompletionName, + request, new LSP.ClientCapabilities(), null, CancellationToken.None); + Contract.ThrowIfNull(response); + return response; + } +} diff --git a/src/Features/LanguageServer/ProtocolUnitTests/InlineCompletions/TestSnippetInfoService.cs b/src/Features/LanguageServer/ProtocolUnitTests/InlineCompletions/TestSnippetInfoService.cs new file mode 100644 index 0000000000000..cc832b1d9090f --- /dev/null +++ b/src/Features/LanguageServer/ProtocolUnitTests/InlineCompletions/TestSnippetInfoService.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Composition; +using System.IO; +using System.Linq; +using System.Xml.Linq; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LanguageServer.Handler.InlineCompletions; +using Microsoft.CodeAnalysis.Snippets; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests; + +[ExportLanguageService(typeof(ISnippetInfoService), LanguageNames.CSharp), Shared, PartNotDiscoverable] +internal class TestSnippetInfoService : ISnippetInfoService +{ + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public TestSnippetInfoService() + { + } + + public IEnumerable GetSnippetsIfAvailable() + { + var snippetsFile = Path.Combine(Directory.GetCurrentDirectory(), "InlineCompletions", "TestSnippets.snippet"); + if (!File.Exists(snippetsFile)) + { + throw new InvalidOperationException($"Could not find test snippets file at {snippetsFile}"); + } + + var testSnippetsXml = XDocument.Load(snippetsFile); + var snippets = InlineCompletionsHandler.CodeSnippet.ReadSnippets(testSnippetsXml); + Contract.ThrowIfNull(snippets); + + var snippetInfos = snippets.Value.Select(s => new SnippetInfo(s.Shortcut, s.Title, s.Title, snippetsFile)); + return snippetInfos; + } + + public bool ShouldFormatSnippet(SnippetInfo snippetInfo) + { + throw new NotImplementedException(); + } + + public bool SnippetShortcutExists_NonBlocking(string shortcut) + { + throw new NotImplementedException(); + } +} diff --git a/src/Features/LanguageServer/ProtocolUnitTests/InlineCompletions/TestSnippets.snippet b/src/Features/LanguageServer/ProtocolUnitTests/InlineCompletions/TestSnippets.snippet new file mode 100644 index 0000000000000..27ed77f9d49f4 --- /dev/null +++ b/src/Features/LanguageServer/ProtocolUnitTests/InlineCompletions/TestSnippets.snippet @@ -0,0 +1,190 @@ + + + +
+ ctor + ctor + Code snippet for constructor + Microsoft Corporation + + Expansion + +
+ + + + classname + Class name + ClassName() + ClassNamePlaceholder + + + + + + +
+ +
+ if + if + Code snippet for if statement + Microsoft Corporation + + Expansion + SurroundsWith + +
+ + + + expression + Expression to evaluate + true + + + + + + +
+ +
+ for + for + Code snippet for 'for' loop + Microsoft Corporation + + Expansion + SurroundsWith + +
+ + + + index + i + Index + + + max + length + Max length + + + + + + +
+ +
+ cw + cw + Code snippet for Console.WriteLine + Microsoft Corporation + + Expansion + +
+ + + + SystemConsole + SimpleTypeName(global::System.Console) + + + + + + +
+ +
+ switch + switch + Code snippet for switch statement + Microsoft Corporation + + Expansion + +
+ + + + expression + Expression to switch on + switch_on + + + cases + GenerateSwitchCases($expression$) + default: + + + + + + +
+ +
+ equals + equals + Code snippet for implementing Equals() according to guidelines + Microsoft Corporation + + Expansion + +
+ + + + Exception + SimpleTypeName(global::System.NotImplementedException) + + + + + + +
+
\ No newline at end of file diff --git a/src/Features/LanguageServer/ProtocolUnitTests/LanguageServerTargetTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/LanguageServerTargetTests.cs index b27ade5026b05..9556f4a82ad74 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/LanguageServerTargetTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/LanguageServerTargetTests.cs @@ -98,8 +98,7 @@ private LanguageServerTarget CreateLanguageServer(out JsonRpc serverJsonRpc) NoOpLspLogger.Instance, ProtocolConstants.RoslynLspLanguages, clientName: null, - userVisibleServerName: string.Empty, - telemetryServerTypeName: string.Empty); + WellKnownLspServerKinds.AlwaysActiveVSLspServer); serverJsonRpc.StartListening(); return languageServer; diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Microsoft.CodeAnalysis.LanguageServer.Protocol.UnitTests.csproj b/src/Features/LanguageServer/ProtocolUnitTests/Microsoft.CodeAnalysis.LanguageServer.Protocol.UnitTests.csproj index 19c77c14e8a2b..72a4d3b21c333 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Microsoft.CodeAnalysis.LanguageServer.Protocol.UnitTests.csproj +++ b/src/Features/LanguageServer/ProtocolUnitTests/Microsoft.CodeAnalysis.LanguageServer.Protocol.UnitTests.csproj @@ -8,6 +8,11 @@ Microsoft.CodeAnalysis.LanguageServer.UnitTests UnitTest + + + Always + + diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Ordering/FailingMutatingRequestHandler.cs b/src/Features/LanguageServer/ProtocolUnitTests/Ordering/FailingMutatingRequestHandler.cs index 3f57adc4f3ae3..95ffc9ac764e9 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Ordering/FailingMutatingRequestHandler.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Ordering/FailingMutatingRequestHandler.cs @@ -23,7 +23,7 @@ public FailingMutatingRequestHandlerProvider() { } - public override ImmutableArray CreateRequestHandlers() + public override ImmutableArray CreateRequestHandlers(WellKnownLspServerKinds serverKind) { return ImmutableArray.Create(new FailingMutatingRequestHandler()); } diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Ordering/FailingRequestHandler.cs b/src/Features/LanguageServer/ProtocolUnitTests/Ordering/FailingRequestHandler.cs index 2acd55dd2a0b7..b655d3aa53504 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Ordering/FailingRequestHandler.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Ordering/FailingRequestHandler.cs @@ -25,7 +25,7 @@ public FailingRequestHandlerProvider() { } - public override ImmutableArray CreateRequestHandlers() + public override ImmutableArray CreateRequestHandlers(WellKnownLspServerKinds serverKind) { return ImmutableArray.Create(new FailingRequestHandler()); } diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Ordering/LongRunningNonMutatingRequestHandler.cs b/src/Features/LanguageServer/ProtocolUnitTests/Ordering/LongRunningNonMutatingRequestHandler.cs index 510a7f80dee96..112aecd50dee0 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Ordering/LongRunningNonMutatingRequestHandler.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Ordering/LongRunningNonMutatingRequestHandler.cs @@ -26,7 +26,7 @@ public LongRunningNonMutatingRequestHandlerProvider() { } - public override ImmutableArray CreateRequestHandlers() => ImmutableArray.Create(new LongRunningNonMutatingRequestHandler()); + public override ImmutableArray CreateRequestHandlers(WellKnownLspServerKinds serverKind) => ImmutableArray.Create(new LongRunningNonMutatingRequestHandler()); } internal class LongRunningNonMutatingRequestHandler : IRequestHandler diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Ordering/MutatingRequestHandler.cs b/src/Features/LanguageServer/ProtocolUnitTests/Ordering/MutatingRequestHandler.cs index 22f53660a6c55..f2dfeed623a38 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Ordering/MutatingRequestHandler.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Ordering/MutatingRequestHandler.cs @@ -24,7 +24,7 @@ public MutatingRequestHandlerProvider() { } - public override ImmutableArray CreateRequestHandlers() + public override ImmutableArray CreateRequestHandlers(WellKnownLspServerKinds serverKind) { return ImmutableArray.Create(new MutatingRequestHandler()); } diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Ordering/NonLSPSolutionRequestHandlerProvider.cs b/src/Features/LanguageServer/ProtocolUnitTests/Ordering/NonLSPSolutionRequestHandlerProvider.cs index 577580d6b689f..74b4e67e6b70e 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Ordering/NonLSPSolutionRequestHandlerProvider.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Ordering/NonLSPSolutionRequestHandlerProvider.cs @@ -26,7 +26,7 @@ public NonLSPSolutionRequestHandlerProvider() { } - public override ImmutableArray CreateRequestHandlers() + public override ImmutableArray CreateRequestHandlers(WellKnownLspServerKinds serverKind) { return ImmutableArray.Create(new NonLSPSolutionRequestHandler()); } diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Ordering/NonMutatingRequestHandler.cs b/src/Features/LanguageServer/ProtocolUnitTests/Ordering/NonMutatingRequestHandler.cs index 04549aa0f4a33..03bedb57afc54 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Ordering/NonMutatingRequestHandler.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Ordering/NonMutatingRequestHandler.cs @@ -24,7 +24,7 @@ public NonMutatingRequestHandlerProvider() { } - public override ImmutableArray CreateRequestHandlers() + public override ImmutableArray CreateRequestHandlers(WellKnownLspServerKinds serverKind) { return ImmutableArray.Create(new NonMutatingRequestHandler()); } diff --git a/src/Features/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs index bce9d51c8a109..85f8c12cd37fc 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs @@ -3,17 +3,15 @@ // See the LICENSE file in the project root for more information. using System; -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.LanguageServer.UnitTests.Completion; -using Microsoft.CodeAnalysis.LanguageServer.UnitTests.ProjectContext; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; -using Microsoft.CodeAnalysis.UnitTests; +using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.LanguageServer.Protocol; using Roslyn.Test.Utilities; using Xunit; @@ -145,45 +143,6 @@ public async Task TestForksOnProjectChangesAsync() Assert.Equal("NewCSProj1", openedDocument.Project.AssemblyName); } - [Fact] - public async Task TestForksOnOptionChangesChangesAsync() - { - var markup = -@"using System; -class A -{ - void M() - { - DateTime.Now.ToString(""{|caret:|}); - } -}"; - using var testLspServer = await CreateTestLspServerAsync(markup); - var documentUri = testLspServer.GetCurrentSolution().Projects.First().Documents.Single(d => d.FilePath!.Contains("test1")).GetURI(); - - // Open the document via LSP to create the initial LSP solution. - await OpenDocumentAndVerifyLspTextAsync(documentUri, testLspServer, markup); - - var completionParams = CreateCompletionParams( - testLspServer.GetLocations("caret").Single(), - invokeKind: VSInternalCompletionInvokeKind.Typing, - triggerCharacter: "\"", - triggerKind: CompletionTriggerKind.TriggerCharacter); - var completionItems = await CompletionTests.RunGetCompletionsAsync(testLspServer, completionParams); - Assert.Contains(completionItems.Items, item => item.Label == "d"); - - // Modify an option via the workspace. - var solutionWithChangedOption = testLspServer.TestWorkspace.CurrentSolution.WithOptions( - testLspServer.TestWorkspace.Options.WithChangedOption(CodeAnalysis.Completion.CompletionOptions.Metadata.ProvideDateAndTimeCompletions, LanguageNames.CSharp, false)); - await testLspServer.TestWorkspace.ChangeSolutionAsync(solutionWithChangedOption); - - // Assert that the LSP incremental solution is cleared. - Assert.Null(GetManagerWorkspaceState(testLspServer.TestWorkspace, testLspServer)); - - // Verify that we fork again from the workspace and the new LSP solution has the new text and respects the updated option. - completionItems = await CompletionTests.RunGetCompletionsAsync(testLspServer, completionParams); - Assert.Null(completionItems); - } - [Fact] public async Task TestDoesNotForkOnOpenDocumentWorkspaceEventAsync() { diff --git a/src/Features/VisualBasic/Portable/AddImport/VisualBasicAddImportFeatureService.vb b/src/Features/VisualBasic/Portable/AddImport/VisualBasicAddImportFeatureService.vb index 9583478f889dc..ba19c8c027d2e 100644 --- a/src/Features/VisualBasic/Portable/AddImport/VisualBasicAddImportFeatureService.vb +++ b/src/Features/VisualBasic/Portable/AddImport/VisualBasicAddImportFeatureService.vb @@ -5,7 +5,6 @@ Imports System.Composition Imports System.Threading Imports Microsoft.CodeAnalysis.AddImport -Imports Microsoft.CodeAnalysis.AddImports Imports Microsoft.CodeAnalysis.CaseCorrection Imports Microsoft.CodeAnalysis.CodeGeneration Imports Microsoft.CodeAnalysis.Diagnostics @@ -13,9 +12,7 @@ Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.LanguageServices -Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Simplification -Imports Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.AddImport @@ -188,12 +185,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.AddImport End Function Protected Overrides Function GetDescription( - document As Document, - preferences As CodeGenerationPreferences, - symbol As INamespaceOrTypeSymbol, - semanticModel As SemanticModel, - root As SyntaxNode, - cancellationToken As CancellationToken) As (description As String, hasExistingImport As Boolean) + document As Document, + options As AddImportPlacementOptions, + symbol As INamespaceOrTypeSymbol, + semanticModel As SemanticModel, + root As SyntaxNode, + cancellationToken As CancellationToken) As (description As String, hasExistingImport As Boolean) Dim importsStatement = GetImportsStatement(symbol) Dim addImportService = document.GetLanguageService(Of IAddImportsService) @@ -282,28 +279,27 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.AddImport contextNode As SyntaxNode, symbol As INamespaceOrTypeSymbol, document As Document, - allowInHiddenRegions As Boolean, + options As AddImportPlacementOptions, cancellationToken As CancellationToken) As Task(Of Document) Dim importsStatement = GetImportsStatement(symbol) - Return Await AddImportAsync( - contextNode, document, allowInHiddenRegions, - importsStatement, cancellationToken).ConfigureAwait(False) + Return Await AddImportAsync(contextNode, document, importsStatement, options, cancellationToken).ConfigureAwait(False) End Function Private Overloads Shared Async Function AddImportAsync( - contextNode As SyntaxNode, document As Document, - allowInHiddenRegions As Boolean, - importsStatement As ImportsStatementSyntax, cancellationToken As CancellationToken) As Task(Of Document) + contextNode As SyntaxNode, + document As Document, + importsStatement As ImportsStatementSyntax, + options As AddImportPlacementOptions, + cancellationToken As CancellationToken) As Task(Of Document) - Dim preferences = Await VisualBasicCodeGenerationPreferences.FromDocumentAsync(document, cancellationToken).ConfigureAwait(False) Dim compilation = Await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(False) Dim importService = document.GetLanguageService(Of IAddImportsService) Dim generator = SyntaxGenerator.GetGenerator(document) Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) - Dim newRoot = importService.AddImport(compilation, root, contextNode, importsStatement, generator, preferences, allowInHiddenRegions, cancellationToken) + Dim newRoot = importService.AddImport(compilation, root, contextNode, importsStatement, generator, options, cancellationToken) newRoot = newRoot.WithAdditionalAnnotations(CaseCorrector.Annotation, Formatter.Annotation) Dim newDocument = document.WithSyntaxRoot(newRoot) @@ -314,15 +310,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.AddImport contextNode As SyntaxNode, nameSpaceParts As IReadOnlyList(Of String), document As Document, - allowInHiddenRegions As Boolean, + options As AddImportPlacementOptions, cancellationToken As CancellationToken) As Task(Of Document) Dim nameSyntax = CreateNameSyntax(nameSpaceParts, nameSpaceParts.Count - 1) Dim importsStatement = GetImportsStatement(nameSyntax) - Return AddImportAsync( - contextNode, document, - allowInHiddenRegions, - importsStatement, cancellationToken) + Return AddImportAsync(contextNode, document, importsStatement, options, cancellationToken) End Function Private Function CreateNameSyntax(nameSpaceParts As IReadOnlyList(Of String), index As Integer) As NameSyntax diff --git a/src/Features/VisualBasic/Portable/CodeFixes/Suppression/VisualBasicSuppressionCodeFixProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/Suppression/VisualBasicSuppressionCodeFixProvider.vb index 8e03fe3750f60..bafe833e5ac81 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/Suppression/VisualBasicSuppressionCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/Suppression/VisualBasicSuppressionCodeFixProvider.vb @@ -6,7 +6,7 @@ Imports System.Composition Imports System.Diagnostics.CodeAnalysis Imports System.Globalization Imports System.Threading -Imports Microsoft.CodeAnalysis.AddImports +Imports Microsoft.CodeAnalysis.AddImport Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.CodeFixes.Suppression Imports Microsoft.CodeAnalysis.Formatting diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ImportCompletionProvider/ExtensionMethodImportCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ImportCompletionProvider/ExtensionMethodImportCompletionProvider.vb index d3b58bf5a44b6..f2002af0362a8 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ImportCompletionProvider/ExtensionMethodImportCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ImportCompletionProvider/ExtensionMethodImportCompletionProvider.vb @@ -8,8 +8,6 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Completion.Providers Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.Options -Imports Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery Imports Microsoft.CodeAnalysis.Text Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers @@ -43,10 +41,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Public Overrides ReadOnly Property TriggerCharacters As ImmutableHashSet(Of Char) = CompletionUtilities.CommonTriggerCharsAndParen - Protected Overrides Function CreateContextAsync(document As Document, position As Integer, cancellationToken As CancellationToken) As Task(Of SyntaxContext) - Return ImportCompletionProviderHelper.CreateContextAsync(document, position, cancellationToken) - End Function - Protected Overrides Function GetImportedNamespaces(location As SyntaxNode, semanticModel As SemanticModel, cancellationToken As CancellationToken) As ImmutableArray(Of String) Return ImportCompletionProviderHelper.GetImportedNamespaces(location, semanticModel) End Function diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ImportCompletionProvider/ImportCompletionProviderHelper.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ImportCompletionProvider/ImportCompletionProviderHelper.vb index d3d346e1aab02..5a09a6ad7633a 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ImportCompletionProvider/ImportCompletionProviderHelper.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ImportCompletionProvider/ImportCompletionProviderHelper.vb @@ -3,10 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Collections.Immutable -Imports System.Threading Imports Microsoft.CodeAnalysis.PooledObjects -Imports Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery -Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers @@ -29,13 +26,5 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Return builder.ToImmutableAndFree() End Function - - Public Shared Async Function CreateContextAsync(document As Document, position As Integer, cancellationToken As CancellationToken) As Task(Of SyntaxContext) - ' 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. - Dim semanticModel = (Await document.GetPartialSemanticModelAsync(cancellationToken).ConfigureAwait(False)).semanticModel - Contract.ThrowIfNull(semanticModel) - Return VisualBasicSyntaxContext.CreateContext(document, semanticModel, position, cancellationToken) - End Function End Class End Namespace diff --git a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ImportCompletionProvider/TypeImportCompletionProvider.vb b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ImportCompletionProvider/TypeImportCompletionProvider.vb index 0e7557326bbcf..bf843dc88aa0d 100644 --- a/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ImportCompletionProvider/TypeImportCompletionProvider.vb +++ b/src/Features/VisualBasic/Portable/Completion/CompletionProviders/ImportCompletionProvider/TypeImportCompletionProvider.vb @@ -8,8 +8,6 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Completion.Providers Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.Options -Imports Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -38,10 +36,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Public Overrides ReadOnly Property TriggerCharacters As ImmutableHashSet(Of Char) = CompletionUtilities.CommonTriggerCharsAndParen - Protected Overrides Function CreateContextAsync(document As Document, position As Integer, cancellationToken As CancellationToken) As Task(Of SyntaxContext) - Return ImportCompletionProviderHelper.CreateContextAsync(document, position, cancellationToken) - End Function - Protected Overrides Function GetImportedNamespaces(location As SyntaxNode, semanticModel As SemanticModel, cancellationToken As CancellationToken) As ImmutableArray(Of String) Return ImportCompletionProviderHelper.GetImportedNamespaces(location, semanticModel) End Function diff --git a/src/Features/VisualBasic/Portable/DocumentationComments/VisualBasicDocumentationCommentSnippetService.vb b/src/Features/VisualBasic/Portable/DocumentationComments/VisualBasicDocumentationCommentSnippetService.vb index 9fb38c283f28a..3785554dfbc0f 100644 --- a/src/Features/VisualBasic/Portable/DocumentationComments/VisualBasicDocumentationCommentSnippetService.vb +++ b/src/Features/VisualBasic/Portable/DocumentationComments/VisualBasicDocumentationCommentSnippetService.vb @@ -109,10 +109,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.DocumentationComments Return count End Function - Protected Overrides Function IsMemberDeclaration(member As DeclarationStatementSyntax) As Boolean - Return member.IsMemberDeclaration() - End Function - Protected Overrides Function GetDocumentationCommentStubLines(member As DeclarationStatementSyntax) As List(Of String) Dim list = New List(Of String) From { "''' ", diff --git a/src/Features/VisualBasic/Portable/EmbeddedLanguages/EmbeddedLanguageUtilities.vb b/src/Features/VisualBasic/Portable/EmbeddedLanguages/EmbeddedLanguageUtilities.vb index 7e61f5d32c276..5502b5ac6e377 100644 --- a/src/Features/VisualBasic/Portable/EmbeddedLanguages/EmbeddedLanguageUtilities.vb +++ b/src/Features/VisualBasic/Portable/EmbeddedLanguages/EmbeddedLanguageUtilities.vb @@ -2,8 +2,22 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports Microsoft.CodeAnalysis.Editing +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax + Namespace Microsoft.CodeAnalysis.VisualBasic.Features.EmbeddedLanguages Friend Module EmbeddedLanguageUtilities + Friend Sub AddComment(editor As SyntaxEditor, stringLiteral As SyntaxToken, commentContents As String) + Dim trivia = SyntaxFactory.TriviaList( + SyntaxFactory.CommentTrivia($"' {commentContents}"), + SyntaxFactory.ElasticCarriageReturnLineFeed) + Dim containingStatement = stringLiteral.Parent.GetAncestor(Of StatementSyntax) + Dim leadingBlankLines = containingStatement.GetLeadingBlankLines() + Dim newStatement = containingStatement.GetNodeWithoutLeadingBlankLines(). + WithPrependedLeadingTrivia(leadingBlankLines.AddRange(trivia)) + editor.ReplaceNode(containingStatement, newStatement) + End Sub + Public Function EscapeText(text As String) As String ' VB has no need to escape any regex characters that would be passed in through this API. Return text diff --git a/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicEmbeddedLanguageFeaturesProvider.vb b/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicEmbeddedLanguageFeaturesProvider.vb index 8c27c3d84d811..3cd54bfec0b23 100644 --- a/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicEmbeddedLanguageFeaturesProvider.vb +++ b/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicEmbeddedLanguageFeaturesProvider.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/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicJsonDetectionAnalyzer.vb b/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicJsonDetectionAnalyzer.vb new file mode 100644 index 0000000000000..c0fa023b3df78 --- /dev/null +++ b/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicJsonDetectionAnalyzer.vb @@ -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. + +Imports Microsoft.CodeAnalysis.Diagnostics +Imports Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.EmbeddedLanguages.LanguageServices + +Namespace Microsoft.CodeAnalysis.VisualBasic.Features.EmbeddedLanguages + + Friend Class VisualBasicJsonDetectionAnalyzer + Inherits AbstractJsonDetectionAnalyzer + + Public Sub New() + MyBase.New(VisualBasicEmbeddedLanguagesProvider.Info) + End Sub + End Class +End Namespace diff --git a/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicJsonDetectionCodeFixProvider.vb b/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicJsonDetectionCodeFixProvider.vb new file mode 100644 index 0000000000000..309a9b28fd57e --- /dev/null +++ b/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicJsonDetectionCodeFixProvider.vb @@ -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. + +Imports System.Composition +Imports Microsoft.CodeAnalysis.CodeFixes +Imports Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices +Imports Microsoft.CodeAnalysis.Host.Mef +Imports Microsoft.CodeAnalysis.VisualBasic.EmbeddedLanguages.LanguageServices + +Namespace Microsoft.CodeAnalysis.VisualBasic.Features.EmbeddedLanguages + + Friend Class VisualBasicJsonDetectionCodeFixProvider + Inherits AbstractJsonDetectionCodeFixProvider + + + + Public Sub New() + MyBase.New(VisualBasicEmbeddedLanguagesProvider.Info) + End Sub + + Protected Overrides Sub AddComment(editor As CodeAnalysis.Editing.SyntaxEditor, stringLiteral As SyntaxToken, commentContents As String) + EmbeddedLanguageUtilities.AddComment(editor, stringLiteral, commentContents) + End Sub + End Class +End Namespace diff --git a/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicJsonDiagnosticAnalyzer.vb b/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicJsonDiagnosticAnalyzer.vb new file mode 100644 index 0000000000000..f952ebdd0f834 --- /dev/null +++ b/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicJsonDiagnosticAnalyzer.vb @@ -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. + +Imports Microsoft.CodeAnalysis.Diagnostics +Imports Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json.LanguageServices +Imports Microsoft.CodeAnalysis.VisualBasic.EmbeddedLanguages.LanguageServices + +Namespace Microsoft.CodeAnalysis.VisualBasic.Features.EmbeddedLanguages + + Friend Class VisualBasicJsonDiagnosticAnalyzer + Inherits AbstractJsonDiagnosticAnalyzer + + Public Sub New() + MyBase.New(VisualBasicEmbeddedLanguagesProvider.Info) + End Sub + End Class +End Namespace diff --git a/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicRegexDiagnosticAnalyzer.vb b/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicRegexDiagnosticAnalyzer.vb index 9b1a1b4a11d1c..681c492e866f2 100644 --- a/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicRegexDiagnosticAnalyzer.vb +++ b/src/Features/VisualBasic/Portable/EmbeddedLanguages/VisualBasicRegexDiagnosticAnalyzer.vb @@ -3,7 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports Microsoft.CodeAnalysis.Diagnostics -Imports Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions +Imports Microsoft.CodeAnalysis.Features.EmbeddedLanguages.RegularExpressions.LanguageServices Imports Microsoft.CodeAnalysis.VisualBasic.EmbeddedLanguages.LanguageServices Namespace Microsoft.CodeAnalysis.VisualBasic.Features.EmbeddedLanguages diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/AccessorDeclarationHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/AccessorDeclarationHighlighter.vb similarity index 90% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/AccessorDeclarationHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/AccessorDeclarationHighlighter.vb index 20a5f0b25b684..712f2e1368d08 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/AccessorDeclarationHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/AccessorDeclarationHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class AccessorDeclarationHighlighter Inherits AbstractKeywordHighlighter(Of SyntaxNode) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/ConditionalPreprocessorHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/ConditionalPreprocessorHighlighter.vb similarity index 90% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/ConditionalPreprocessorHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/ConditionalPreprocessorHighlighter.vb index 3485505ca11e0..9b6f474555e5a 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/ConditionalPreprocessorHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/ConditionalPreprocessorHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class ConditionalPreprocessorHighlighter Inherits AbstractKeywordHighlighter(Of DirectiveTriviaSyntax) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/ConstructorDeclarationHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/ConstructorDeclarationHighlighter.vb similarity index 87% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/ConstructorDeclarationHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/ConstructorDeclarationHighlighter.vb index 40e1b671233b7..b8ed2d1c20948 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/ConstructorDeclarationHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/ConstructorDeclarationHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class ConstructorDeclarationHighlighter Inherits AbstractKeywordHighlighter(Of SyntaxNode) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/DoLoopBlockHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/DoLoopBlockHighlighter.vb similarity index 89% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/DoLoopBlockHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/DoLoopBlockHighlighter.vb index bf5e19a8913c8..219befa11794b 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/DoLoopBlockHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/DoLoopBlockHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class DoLoopBlockHighlighter Inherits AbstractKeywordHighlighter(Of SyntaxNode) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/EnumBlockHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/EnumBlockHighlighter.vb similarity index 87% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/EnumBlockHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/EnumBlockHighlighter.vb index 3c85a3925e393..aa3e474ffef81 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/EnumBlockHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/EnumBlockHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class EnumBlockHighlighter Inherits AbstractKeywordHighlighter(Of SyntaxNode) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/EventBlockHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/EventBlockHighlighter.vb similarity index 87% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/EventBlockHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/EventBlockHighlighter.vb index 77db97226a30d..6ce6cb255d4ed 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/EventBlockHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/EventBlockHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class EventBlockHighlighter Inherits AbstractKeywordHighlighter(Of SyntaxNode) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/EventDeclarationHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/EventDeclarationHighlighter.vb similarity index 87% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/EventDeclarationHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/EventDeclarationHighlighter.vb index 527155982c6de..a9284fa00e6c3 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/EventDeclarationHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/EventDeclarationHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class EventDeclarationHighlighter Inherits AbstractKeywordHighlighter(Of EventStatementSyntax) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/ForLoopBlockHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/ForLoopBlockHighlighter.vb similarity index 95% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/ForLoopBlockHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/ForLoopBlockHighlighter.vb index 749795317652e..862d26610af0d 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/ForLoopBlockHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/ForLoopBlockHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class ForLoopBlockHighlighter Inherits AbstractKeywordHighlighter(Of SyntaxNode) @@ -39,7 +39,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting highlights.Add(.InKeyword.Span) End With Else - throw ExceptionUtilities.UnexpectedValue(forBlock.ForOrForEachStatement) + Throw ExceptionUtilities.UnexpectedValue(forBlock.ForOrForEachStatement) End If highlights.AddRange( diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/MethodDeclarationHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/MethodDeclarationHighlighter.vb similarity index 91% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/MethodDeclarationHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/MethodDeclarationHighlighter.vb index a84dc02581c0d..3a42bb5fdb463 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/MethodDeclarationHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/MethodDeclarationHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class MethodDeclarationHighlighter Inherits AbstractKeywordHighlighter(Of SyntaxNode) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/MultiLineIfBlockHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/MultiLineIfBlockHighlighter.vb similarity index 89% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/MultiLineIfBlockHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/MultiLineIfBlockHighlighter.vb index 1629730cec8d2..46fbe4a4ef872 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/MultiLineIfBlockHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/MultiLineIfBlockHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class MultiLineIfBlockHighlighter Inherits AbstractKeywordHighlighter(Of MultiLineIfBlockSyntax) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/MultiLineLambdaExpressionHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/MultiLineLambdaExpressionHighlighter.vb similarity index 90% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/MultiLineLambdaExpressionHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/MultiLineLambdaExpressionHighlighter.vb index 306fbf68e7333..e3ba9ea9686ad 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/MultiLineLambdaExpressionHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/MultiLineLambdaExpressionHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class MultiLineLambdaExpressionHighlighter Inherits AbstractKeywordHighlighter(Of SyntaxNode) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/NamespaceBlockHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/NamespaceBlockHighlighter.vb similarity index 83% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/NamespaceBlockHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/NamespaceBlockHighlighter.vb index 70f5514630ba3..8dd0c5194aa88 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/NamespaceBlockHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/NamespaceBlockHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class NamespaceBlockHighlighter Inherits AbstractKeywordHighlighter(Of SyntaxNode) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/OperatorDeclarationHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/OperatorDeclarationHighlighter.vb similarity index 87% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/OperatorDeclarationHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/OperatorDeclarationHighlighter.vb index bafa1b20ce712..dc5290ce338e4 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/OperatorDeclarationHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/OperatorDeclarationHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class OperatorDeclarationHighlighter Inherits AbstractKeywordHighlighter(Of SyntaxNode) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/PropertyBlockHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/PropertyBlockHighlighter.vb similarity index 90% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/PropertyBlockHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/PropertyBlockHighlighter.vb index ab0c98cf8d3a5..b18192fa831d7 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/PropertyBlockHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/PropertyBlockHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - + Friend Class PropertyBlockHighlighter Inherits AbstractKeywordHighlighter(Of SyntaxNode) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/PropertyDeclarationHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/PropertyDeclarationHighlighter.vb similarity index 87% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/PropertyDeclarationHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/PropertyDeclarationHighlighter.vb index ed0ec761c414b..29fe23d3acafb 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/PropertyDeclarationHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/PropertyDeclarationHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class PropertyDeclarationHighlighter Inherits AbstractKeywordHighlighter(Of PropertyStatementSyntax) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/RegionHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/RegionHighlighter.vb similarity index 89% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/RegionHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/RegionHighlighter.vb index 1757d4df2dcc3..2439b87678ad9 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/RegionHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/RegionHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class RegionHighlighter Inherits AbstractKeywordHighlighter(Of DirectiveTriviaSyntax) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/SelectBlockHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/SelectBlockHighlighter.vb similarity index 90% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/SelectBlockHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/SelectBlockHighlighter.vb index 7e54a89c152cf..639535056774e 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/SelectBlockHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/SelectBlockHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class SelectBlockHighlighter Inherits AbstractKeywordHighlighter(Of SyntaxNode) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/SingleLineIfBlockHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/SingleLineIfBlockHighlighter.vb similarity index 82% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/SingleLineIfBlockHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/SingleLineIfBlockHighlighter.vb index 856eb4803c474..2d8e2b7869e07 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/SingleLineIfBlockHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/SingleLineIfBlockHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class SingleLineIfBlockHighlighter Inherits AbstractKeywordHighlighter(Of SingleLineIfStatementSyntax) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/SyncLockBlockHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/SyncLockBlockHighlighter.vb similarity index 83% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/SyncLockBlockHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/SyncLockBlockHighlighter.vb index 18ce9c134374b..da8cb22e46f99 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/SyncLockBlockHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/SyncLockBlockHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class SyncLockBlockHighlighter Inherits AbstractKeywordHighlighter(Of SyntaxNode) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/TryBlockHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/TryBlockHighlighter.vb similarity index 92% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/TryBlockHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/TryBlockHighlighter.vb index 05d606df0f3db..faf02ab7d0985 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/TryBlockHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/TryBlockHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class TryBlockHighlighter Inherits AbstractKeywordHighlighter(Of SyntaxNode) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/TypeBlockHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/TypeBlockHighlighter.vb similarity index 88% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/TypeBlockHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/TypeBlockHighlighter.vb index 13d7949e7d030..bb9ea3fa547eb 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/TypeBlockHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/TypeBlockHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class TypeBlockHighlighter Inherits AbstractKeywordHighlighter(Of SyntaxNode) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/UsingBlockHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/UsingBlockHighlighter.vb similarity index 82% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/UsingBlockHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/UsingBlockHighlighter.vb index 3c0a4276c34c0..76a7277a68c29 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/UsingBlockHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/UsingBlockHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class UsingBlockHighlighter Inherits AbstractKeywordHighlighter(Of SyntaxNode) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/WhileBlockHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/WhileBlockHighlighter.vb similarity index 86% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/WhileBlockHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/WhileBlockHighlighter.vb index 98fc7b8ad1efe..f71ec26029b2f 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/WhileBlockHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/WhileBlockHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class WhileBlockHighlighter Inherits AbstractKeywordHighlighter(Of SyntaxNode) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/WithBlockHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/WithBlockHighlighter.vb similarity index 82% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/WithBlockHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/WithBlockHighlighter.vb index 8c238aabfb7e3..948cdf1a0931e 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/WithBlockHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/WithBlockHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class WithBlockHighlighter Inherits AbstractKeywordHighlighter(Of SyntaxNode) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/XmlCDataHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/XmlCDataHighlighter.vb similarity index 83% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/XmlCDataHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/XmlCDataHighlighter.vb index ca088a844fe8e..f7af441e5a582 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/XmlCDataHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/XmlCDataHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class XmlCDataHighlighter Inherits AbstractKeywordHighlighter(Of XmlCDataSectionSyntax) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/XmlCommentHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/XmlCommentHighlighter.vb similarity index 83% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/XmlCommentHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/XmlCommentHighlighter.vb index 034061597f54d..cb3971bd323df 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/XmlCommentHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/XmlCommentHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class XmlCommentHighlighter Inherits AbstractKeywordHighlighter(Of XmlCommentSyntax) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/XmlDocumentPrologueHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/XmlDocumentPrologueHighlighter.vb similarity index 84% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/XmlDocumentPrologueHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/XmlDocumentPrologueHighlighter.vb index 58a6e500ae0ea..4b80fb8c530e1 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/XmlDocumentPrologueHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/XmlDocumentPrologueHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class XmlProcessingInstructionHighlighter Inherits AbstractKeywordHighlighter(Of XmlProcessingInstructionSyntax) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/XmlElementHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/XmlElementHighlighter.vb similarity index 87% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/XmlElementHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/XmlElementHighlighter.vb index c09dfc1d81a1b..0ee05887db2eb 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/XmlElementHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/XmlElementHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class XmlElementHighlighter Inherits AbstractKeywordHighlighter(Of XmlNodeSyntax) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/XmlEmbeddedExpressionHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/XmlEmbeddedExpressionHighlighter.vb similarity index 83% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/XmlEmbeddedExpressionHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/XmlEmbeddedExpressionHighlighter.vb index 0b4e70ebcf972..39b7d1c2e6f9e 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/XmlEmbeddedExpressionHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/XmlEmbeddedExpressionHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class XmlEmbeddedExpressionHighlighter Inherits AbstractKeywordHighlighter(Of XmlEmbeddedExpressionSyntax) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/XmlProcessingInstructionHighlighter.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/XmlProcessingInstructionHighlighter.vb similarity index 83% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/XmlProcessingInstructionHighlighter.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/XmlProcessingInstructionHighlighter.vb index 146373acd9a00..7f824c0f44108 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlighters/XmlProcessingInstructionHighlighter.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlighters/XmlProcessingInstructionHighlighter.vb @@ -2,15 +2,15 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.ComponentModel.Composition +Imports System.Composition Imports System.Threading -Imports Microsoft.CodeAnalysis.Editor.Implementation.Highlighting +Imports Microsoft.CodeAnalysis.Highlighting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting - +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting + Friend Class XmlDeclarationHighlighter Inherits AbstractKeywordHighlighter(Of XmlDeclarationSyntax) diff --git a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlightingHelpers.vb b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlightingHelpers.vb similarity index 98% rename from src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlightingHelpers.vb rename to src/Features/VisualBasic/Portable/Highlighting/KeywordHighlightingHelpers.vb index e8e45134f9292..c87c04f3f3e7c 100644 --- a/src/EditorFeatures/VisualBasic/Highlighting/KeywordHighlightingHelpers.vb +++ b/src/Features/VisualBasic/Portable/Highlighting/KeywordHighlightingHelpers.vb @@ -7,7 +7,7 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.KeywordHighlighting +Namespace Microsoft.CodeAnalysis.VisualBasic.KeywordHighlighting Friend Module KeywordHighlightingHelpers Private Sub HighlightRelatedStatements(Of T As SyntaxNode)( diff --git a/src/EditorFeatures/VisualBasic/LineSeparators/VisualBasicLineSeparatorService.vb b/src/Features/VisualBasic/Portable/LineSeparators/VisualBasicLineSeparatorService.vb similarity index 87% rename from src/EditorFeatures/VisualBasic/LineSeparators/VisualBasicLineSeparatorService.vb rename to src/Features/VisualBasic/Portable/LineSeparators/VisualBasicLineSeparatorService.vb index 2d7233579bbc9..29e820fb6bfa6 100644 --- a/src/EditorFeatures/VisualBasic/LineSeparators/VisualBasicLineSeparatorService.vb +++ b/src/Features/VisualBasic/Portable/LineSeparators/VisualBasicLineSeparatorService.vb @@ -2,10 +2,14 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports System.Collections.Immutable Imports System.Composition Imports System.Threading Imports Microsoft.CodeAnalysis.Host.Mef +Imports Microsoft.CodeAnalysis.LineSeparators +Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineSeparators @@ -47,19 +51,20 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineSeparators ''' Given a syntaxTree returns line separator spans. The operation may take fairly long time ''' on a big syntaxTree so it is cancellable. ''' - Public Async Function GetLineSeparatorsAsync(document As Document, - textSpan As TextSpan, - Optional cancellationToken As CancellationToken = Nothing) As Task(Of IEnumerable(Of TextSpan)) Implements ILineSeparatorService.GetLineSeparatorsAsync + Public Async Function GetLineSeparatorsAsync( + document As Document, + textSpan As TextSpan, + cancellationToken As CancellationToken) As Task(Of ImmutableArray(Of TextSpan)) Implements ILineSeparatorService.GetLineSeparatorsAsync Dim syntaxTree = Await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(False) Dim root = Await syntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(False) - Dim spans As New List(Of TextSpan) + Dim spans = ArrayBuilder(Of TextSpan).GetInstance() Dim blocks = root.Traverse(Of SyntaxNode)(textSpan, AddressOf IsSeparableContainer) For Each block In blocks If cancellationToken.IsCancellationRequested Then - Return SpecializedCollections.EmptyList(Of TextSpan)() + Return ImmutableArray(Of TextSpan).Empty End If Dim typeBlock = TryCast(block, TypeBlockSyntax) @@ -87,7 +92,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineSeparators End If Next - Return spans + Return spans.ToImmutable() End Function ''' @@ -95,7 +100,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineSeparators ''' 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 Shared Sub ProcessNodeList(Of T As SyntaxNode)(children As SyntaxList(Of T), spans As List(Of TextSpan), token As CancellationToken) + Private Shared Sub ProcessNodeList(Of T As SyntaxNode)(children As SyntaxList(Of T), spans As ArrayBuilder(Of TextSpan), token As CancellationToken) Contract.ThrowIfNull(spans) If children.Count = 0 Then @@ -130,14 +135,14 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.LineSeparators spans.Add(GetLineSeparatorSpanForNode(nextToLast)) End If - If lastChild.Parent.Kind = SyntaxKind.CompilationUnit Then + If lastChild.Parent.Kind() = SyntaxKind.CompilationUnit Then spans.Add(GetLineSeparatorSpanForNode(lastChild)) End If End If End Sub - Private Shared Sub ProcessImports(importsList As SyntaxList(Of ImportsStatementSyntax), spans As List(Of TextSpan)) + Private Shared Sub ProcessImports(importsList As SyntaxList(Of ImportsStatementSyntax), spans As ArrayBuilder(Of TextSpan)) If importsList.Any() Then spans.Add(GetLineSeparatorSpanForNode(importsList.Last())) End If diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/AbstractIntrinsicOperatorSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/AbstractIntrinsicOperatorSignatureHelpProvider.vb index d44a08ed99e51..82f39a65c0049 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/AbstractIntrinsicOperatorSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/AbstractIntrinsicOperatorSignatureHelpProvider.vb @@ -100,7 +100,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.SignatureHelp argumentName:=Nothing, argumentNames:=Nothing) End Function - Public Overrides Function GetCurrentArgumentState(root As SyntaxNode, position As Integer, syntaxFacts As ISyntaxFactsService, currentSpan As TextSpan, cancellationToken As CancellationToken) As SignatureHelpState + Private Function GetCurrentArgumentState(root As SyntaxNode, position As Integer, syntaxFacts As ISyntaxFactsService, currentSpan As TextSpan, cancellationToken As CancellationToken) As SignatureHelpState Dim node As TSyntaxNode = Nothing If TryGetSyntaxNode(root, position, syntaxFacts, SignatureHelpTriggerReason.InvokeSignatureHelpCommand, cancellationToken, node) AndAlso currentSpan.Start = node.SpanStart Then diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/AttributeSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/AttributeSignatureHelpProvider.vb index fdc4e305051cc..90d944e141a32 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/AttributeSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/AttributeSignatureHelpProvider.vb @@ -92,7 +92,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.SignatureHelp textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken), selectedItem) End Function - Public Overrides Function GetCurrentArgumentState(root As SyntaxNode, position As Integer, syntaxFacts As ISyntaxFactsService, currentSpan As TextSpan, cancellationToken As CancellationToken) As SignatureHelpState + Private Function GetCurrentArgumentState(root As SyntaxNode, position As Integer, syntaxFacts As ISyntaxFactsService, currentSpan As TextSpan, cancellationToken As CancellationToken) As SignatureHelpState Dim expression As AttributeSyntax = Nothing If TryGetAttributeExpression(root, position, syntaxFacts, SignatureHelpTriggerReason.InvokeSignatureHelpCommand, cancellationToken, expression) AndAlso currentSpan.Start = SignatureHelpUtilities.GetSignatureHelpSpan(expression.ArgumentList).Start Then diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/CollectionInitializerSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/CollectionInitializerSignatureHelpProvider.vb index 70d16a12b1381..0aaa13662d39d 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/CollectionInitializerSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/CollectionInitializerSignatureHelpProvider.vb @@ -67,7 +67,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.SignatureHelp textSpan, GetCurrentArgumentState(root, position, syntaxFacts, textSpan, cancellationToken)) End Function - Public Overrides Function GetCurrentArgumentState(root As SyntaxNode, position As Integer, syntaxFacts As ISyntaxFactsService, currentSpan As TextSpan, cancellationToken As CancellationToken) As SignatureHelpState + Private Function GetCurrentArgumentState(root As SyntaxNode, position As Integer, syntaxFacts As ISyntaxFactsService, currentSpan As TextSpan, cancellationToken As CancellationToken) As SignatureHelpState Dim expression As CollectionInitializerSyntax = Nothing If TryGetInitializerExpression( root, diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/FunctionAggregationSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/FunctionAggregationSignatureHelpProvider.vb index 2f4aeb0b93b5f..9a2c0a951093d 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/FunctionAggregationSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/FunctionAggregationSignatureHelpProvider.vb @@ -30,7 +30,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.SignatureHelp Return ch = ")"c End Function - Public Overrides Function GetCurrentArgumentState(root As SyntaxNode, position As Integer, syntaxFacts As ISyntaxFactsService, currentSpan As TextSpan, cancellationToken As CancellationToken) As SignatureHelpState + Private Shared Function GetCurrentArgumentState(root As SyntaxNode, position As Integer, syntaxFacts As ISyntaxFactsService, currentSpan As TextSpan, cancellationToken As CancellationToken) As SignatureHelpState Dim functionAggregation As FunctionAggregationSyntax = Nothing If TryGetFunctionAggregation(root, position, syntaxFacts, SignatureHelpTriggerReason.InvokeSignatureHelpCommand, cancellationToken, functionAggregation) AndAlso functionAggregation.SpanStart = currentSpan.Start Then diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/GenericNameSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/GenericNameSignatureHelpProvider.vb index 085b8c422e278..42c4c0759668c 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/GenericNameSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/GenericNameSignatureHelpProvider.vb @@ -30,7 +30,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.SignatureHelp Return ch = ")"c End Function - Public Overrides Function GetCurrentArgumentState(root As SyntaxNode, position As Integer, syntaxFacts As ISyntaxFactsService, currentSpan As TextSpan, cancellationToken As CancellationToken) As SignatureHelpState + Private Shared Function GetCurrentArgumentState(root As SyntaxNode, position As Integer, syntaxFacts As ISyntaxFactsService, currentSpan As TextSpan, cancellationToken As CancellationToken) As SignatureHelpState Dim expression As GenericNameSyntax = Nothing If TryGetGenericName(root, position, syntaxFacts, SignatureHelpTriggerReason.InvokeSignatureHelpCommand, cancellationToken, expression) AndAlso currentSpan.Start = SignatureHelpUtilities.GetSignatureHelpSpan(expression.TypeArgumentList).Start Then diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.vb index 15d3e4125a37b..435852c85c46c 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/InvocationExpressionSignatureHelpProvider.vb @@ -31,7 +31,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.SignatureHelp Return ch = ")"c End Function - Public Overrides Function GetCurrentArgumentState(root As SyntaxNode, position As Integer, syntaxFacts As ISyntaxFactsService, currentSpan As TextSpan, cancellationToken As CancellationToken) As SignatureHelpState + Private Shared Function GetCurrentArgumentState(root As SyntaxNode, position As Integer, syntaxFacts As ISyntaxFactsService, currentSpan As TextSpan, cancellationToken As CancellationToken) As SignatureHelpState Dim expression As InvocationExpressionSyntax = Nothing If TryGetInvocationExpression(root, position, syntaxFacts, SignatureHelpTriggerReason.InvokeSignatureHelpCommand, cancellationToken, expression) AndAlso currentSpan.Start = GetSignatureHelpSpan(expression.ArgumentList).Start Then diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.vb index 150c0de96046e..4a14fbb26db6b 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/ObjectCreationExpressionSignatureHelpProvider.vb @@ -30,7 +30,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.SignatureHelp Return ch = ")"c End Function - Public Overrides Function GetCurrentArgumentState(root As SyntaxNode, position As Integer, syntaxFacts As ISyntaxFactsService, currentSpan As TextSpan, cancellationToken As CancellationToken) As SignatureHelpState + Private Shared Function GetCurrentArgumentState(root As SyntaxNode, position As Integer, syntaxFacts As ISyntaxFactsService, currentSpan As TextSpan, cancellationToken As CancellationToken) As SignatureHelpState Dim expression As ObjectCreationExpressionSyntax = Nothing If TryGetObjectCreationExpression(root, position, syntaxFacts, SignatureHelpTriggerReason.InvokeSignatureHelpCommand, cancellationToken, expression) AndAlso currentSpan.Start = SignatureHelpUtilities.GetSignatureHelpSpan(expression.ArgumentList).Start Then diff --git a/src/Features/VisualBasic/Portable/SignatureHelp/RaiseEventStatementSignatureHelpProvider.vb b/src/Features/VisualBasic/Portable/SignatureHelp/RaiseEventStatementSignatureHelpProvider.vb index 5e85bcd0c346b..2917c34662e88 100644 --- a/src/Features/VisualBasic/Portable/SignatureHelp/RaiseEventStatementSignatureHelpProvider.vb +++ b/src/Features/VisualBasic/Portable/SignatureHelp/RaiseEventStatementSignatureHelpProvider.vb @@ -29,7 +29,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.SignatureHelp Return False End Function - Public Overrides Function GetCurrentArgumentState(root As SyntaxNode, position As Integer, syntaxFacts As ISyntaxFactsService, currentSpan As TextSpan, cancellationToken As CancellationToken) As SignatureHelpState + Private Shared Function GetCurrentArgumentState(root As SyntaxNode, position As Integer, syntaxFacts As ISyntaxFactsService, currentSpan As TextSpan, cancellationToken As CancellationToken) As SignatureHelpState Dim statement As RaiseEventStatementSyntax = Nothing If TryGetRaiseEventStatement(root, position, syntaxFacts, SignatureHelpTriggerReason.InvokeSignatureHelpCommand, cancellationToken, statement) AndAlso currentSpan.Start = statement.Name.SpanStart Then diff --git a/src/Features/VisualBasic/Portable/Snippets/VisualBasicSnippetFunctionService.vb b/src/Features/VisualBasic/Portable/Snippets/VisualBasicSnippetFunctionService.vb new file mode 100644 index 0000000000000..0c2c67e85a3cf --- /dev/null +++ b/src/Features/VisualBasic/Portable/Snippets/VisualBasicSnippetFunctionService.vb @@ -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. + +Imports System.Composition +Imports System.Threading +Imports Microsoft.CodeAnalysis.Host.Mef +Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax + +Namespace Microsoft.CodeAnalysis.VisualBasic + + + Friend Class VisualBasicSnippetFunctionService + Inherits SnippetFunctionService + + + + Public Sub New() + End Sub + + Public Overrides Async Function GetContainingClassNameAsync(document As Document, position As Integer, cancellationToken As CancellationToken) As Task(Of String) + Dim syntaxTree = Await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(False) + Dim typeBlock = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken).GetAncestor(Of TypeBlockSyntax) + + Return typeBlock.GetNameToken().ValueText + End Function + + Protected Overrides Async Function GetEnumSymbolAsync(document As Document, switchExpressionSpan As TextSpan, cancellationToken As CancellationToken) As Task(Of ITypeSymbol) + Dim syntaxTree = Await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(False) + Dim token = syntaxTree.FindTokenOnRightOfPosition(switchExpressionSpan.Start, cancellationToken) + Dim expressionNode = token.FirstAncestorOrSelf(Function(n) n.Span = switchExpressionSpan) + + If expressionNode Is Nothing Then + Return Nothing + End If + + Dim model As SemanticModel = Await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(False) + Dim typeSymbol = model.GetTypeInfo(expressionNode, cancellationToken).Type + + Return typeSymbol + End Function + + Protected Overrides Async Function GetDocumentWithEnumCaseAsync(document As Document, fullyQualifiedTypeName As String, firstEnumMemberName As String, caseGenerationLocation As TextSpan, cancellationToken As CancellationToken) As Task(Of (Document, TextSpan)) + Dim str = "Case " + fullyQualifiedTypeName + "." + firstEnumMemberName + ":" + vbCrLf + Dim textChange = New TextChange(caseGenerationLocation, str) + Dim typeSpan = New TextSpan(caseGenerationLocation.Start + "Case ".Length, fullyQualifiedTypeName.Length) + + Dim text = Await document.GetTextAsync(cancellationToken).ConfigureAwait(False) + Dim documentWithCaseAdded = document.WithText(text.WithChanges(textChange)) + + Return (documentWithCaseAdded, typeSpan) + End Function + + Public Overrides ReadOnly Property SwitchCaseFormat As String + Get + Return "Case {0}.{1}" & vbCrLf & vbCrLf + End Get + End Property + + Public Overrides ReadOnly Property SwitchDefaultCaseForm As String + Get + Return "Case Else" & vbCrLf + End Get + End Property + End Class +End Namespace diff --git a/src/Test/Diagnostics/DiagnosticOnly_Logger.cs b/src/Test/Diagnostics/DiagnosticOnly_Logger.cs deleted file mode 100644 index f1a5c32e3c51b..0000000000000 --- a/src/Test/Diagnostics/DiagnosticOnly_Logger.cs +++ /dev/null @@ -1,110 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using System; -using System.Diagnostics.Tracing; -using System.Linq; -using System.Threading; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.Options; - -namespace Roslyn.Hosting.Diagnostics -{ - /// - /// provide a way to access internal logging framework - /// - public static class DiagnosticOnly_Logger - { - /// - /// get roslyn event source name - /// - public static string GetRoslynEventSourceName() - { - return EventSource.GetName(typeof(RoslynEventSource)); - } - - /// - /// get roslyn event source guid - /// - public static Guid GetRoslynEventSourceGuid() - { - return EventSource.GetGuid(typeof(RoslynEventSource)); - } - - /// - /// reset logger to default one - /// - public static void ResetLogger() - { - Logger.SetLogger(null); - } - - /// - /// let one such as ETA to set logger for the service layer - /// - internal static void SetLogger(IGlobalOptionService optionsService, string loggerName) - { - if (loggerName == null) - { - ResetLogger(); - } - - Logger.SetLogger(GetLogger(optionsService, loggerName)); - } - - /// - /// get string representation of functionId - /// - public static string GetFunctionId(int functionId) - { - return ((FunctionId)functionId).ToString(); - } - - /// - /// use Roslyn Logger from outside - /// - public static IDisposable LogBlock(string functionId) - { - return Logger.LogBlock(GetFunctionId(functionId), CancellationToken.None); - } - - /// - /// use Roslyn Logger from outside - /// - public static IDisposable LogBlock(string functionId, string message) - { - return Logger.LogBlock(GetFunctionId(functionId), message, CancellationToken.None); - } - - /// - /// get given functionId's int value - /// - public static int GetFunctionIdValue(string functionId) - { - // this will throw if given functionid doesn't exist - return (int)GetFunctionId(functionId); - } - - private static FunctionId GetFunctionId(string functionId) - { - return (FunctionId)Enum.Parse(typeof(FunctionId), functionId); - } - - private static ILogger GetLogger(IGlobalOptionService optionsService, string loggerName) - { - switch (loggerName) - { - case "EtwLogger": - return new EtwLogger(optionsService); - case "TraceLogger": - return new TraceLogger(Logger.GetLoggingChecker(optionsService)); - default: - return EmptyLogger.Instance; - } - } - } -} diff --git a/src/Test/Diagnostics/DiagnosticOnly_TPLListener.cs b/src/Test/Diagnostics/DiagnosticOnly_TPLListener.cs deleted file mode 100644 index b9a753a3fbd10..0000000000000 --- a/src/Test/Diagnostics/DiagnosticOnly_TPLListener.cs +++ /dev/null @@ -1,82 +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.Tracing; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Internal.Log; - -namespace Roslyn.Hosting.Diagnostics -{ - /// - /// This listens to TPL task events. - /// - public static class DiagnosticOnly_TPLListener - { - private static TPLListener s_listener = null; - - public static void Install() - { - // make sure TPL installs its own event source - Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); - - var local = new TPLListener(); - Interlocked.CompareExchange(ref s_listener, local, null); - } - - public static void Uninstall() - { - TPLListener local = null; - Interlocked.Exchange(ref local, s_listener); - - if (local != null) - { - local.Dispose(); - } - } - - private sealed class TPLListener : EventListener - { - private const int EventIdTaskScheduled = 7; - private const int EventIdTaskStarted = 8; - private const int EventIdTaskCompleted = 9; - - public TPLListener() - { - var tplEventSource = EventSource.GetSources().First(e => e.Name == "System.Threading.Tasks.TplEventSource"); - EnableEvents(tplEventSource, EventLevel.LogAlways); - } - - /// - /// Pass TPL events to our logger. - /// - protected override void OnEventWritten(EventWrittenEventArgs eventData) - { - // for now, we just log what TPL already publish, later we actually want to manipulate the information - // and publish that information - switch (eventData.EventId) - { - case EventIdTaskScheduled: - Logger.Log(FunctionId.TPLTask_TaskScheduled, string.Empty); - break; - case EventIdTaskStarted: - Logger.Log(FunctionId.TPLTask_TaskStarted, string.Empty); - break; - case EventIdTaskCompleted: - Logger.Log(FunctionId.TPLTask_TaskCompleted, string.Empty); - break; - default: - // Ignore the rest - break; - } - } - } - } -} diff --git a/src/Test/Diagnostics/Roslyn.Hosting.Diagnostics.csproj b/src/Test/Diagnostics/Roslyn.Hosting.Diagnostics.csproj deleted file mode 100644 index 19069cb566061..0000000000000 --- a/src/Test/Diagnostics/Roslyn.Hosting.Diagnostics.csproj +++ /dev/null @@ -1,26 +0,0 @@ - - - - - Library - Roslyn.Hosting.Diagnostics - net472 - true - - - - - - - - - - - - - - - - - - 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/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/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/IdeBenchmarks/FormatterBenchmarks.cs b/src/Tools/IdeBenchmarks/FormatterBenchmarks.cs index 801a4d2ad8ea4..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; @@ -44,7 +46,7 @@ public object FormatCSharp() using var workspace = TestWorkspace.CreateCSharp(text); var document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id); var root = document.GetSyntaxRootSynchronously(CancellationToken.None); - var options = SyntaxFormattingOptions.Default; + var options = workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService().GetFormattingOptions(DictionaryAnalyzerConfigOptions.Empty); return Formatter.GetFormattedTextChanges(root, workspace.Services, options, CancellationToken.None); } @@ -57,7 +59,7 @@ public object FormatVisualBasic() using var workspace = TestWorkspace.CreateVisualBasic(text); var document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id); var root = document.GetSyntaxRootSynchronously(CancellationToken.None); - var options = SyntaxFormattingOptions.Default; + 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/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/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 7b370876367e7..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; 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..4ff5b21b1d229 100644 --- a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs +++ b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs @@ -131,11 +131,14 @@ 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, 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"; return true; diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml index 2c1019da82c54..a1bdeb49e340d 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml @@ -41,7 +41,7 @@ - + - - @@ -176,13 +171,27 @@ Content="{x:Static local:AdvancedOptionPageStrings.Option_Colorize_regular_expressions}" /> - + + + + + + + + + diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs index 8481b60ff48ad..00323fdfa7cad 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs @@ -17,9 +17,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; @@ -128,8 +129,13 @@ 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(Detect_and_offer_editor_features_for_likely_JSON_strings, JsonFeatureOptions.DetectAndOfferEditorFeaturesForProbableJsonStrings, 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); @@ -179,8 +185,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 +232,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..8ac3b7cce7005 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs @@ -2,8 +2,6 @@ // The .NET 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; namespace Microsoft.VisualStudio.LanguageServices.CSharp.Options @@ -107,14 +105,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 +291,18 @@ 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_Detect_and_offer_editor_features_for_likely_JSON_strings => + ServicesVSResources.Detect_and_offer_editor_features_for_likely_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.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.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/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 57acab1007e6c..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; 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/Options/Readme.md b/src/VisualStudio/CSharp/Impl/Options/Readme.md deleted file mode 100644 index 82e0a0f21f910..0000000000000 --- a/src/VisualStudio/CSharp/Impl/Options/Readme.md +++ /dev/null @@ -1,13 +0,0 @@ -# Adding Options - -To add an option to the options page, follow these instructions. - -1. Determine what page it goes on (Advanced Options, IntelliSenseOptions, NamingStyles, etc) -2. Add the control to the appropriate xaml file -3. Bind the control in the backing cs file. Example from [AdvancedOptionPageControl](https://github.com/dotnet/roslyn/blob/591e899025f1d4cf9bbb6e9af3ef82506b46f501/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs#L43) -```csharp -// BindToOption helper binds known controls, in this case "PlaceSystemNamespaceFirst" -// to the backing "GenerationOptions.PlaceSystemNamespaceFirst" for the language "CSharp" -BindToOption(PlaceSystemNamespaceFirst, GenerationOptions.PlaceSystemNamespaceFirst, LanguageNames.CSharp); -``` -4. If you want the option to be searchable in the search bar, add to [VSPackage.resx](https://github.com/dotnet/roslyn/blob/591e899025f1d4cf9bbb6e9af3ef82506b46f501/src/VisualStudio/CSharp/Impl/VSPackage.resx) in the appropriate block. Each block of terms has a comment describing what page it's for. 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/SnippetExpansionClient.cs b/src/VisualStudio/CSharp/Impl/Snippets/SnippetExpansionClient.cs index 089069700186b..d875e7e6382b4 100644 --- a/src/VisualStudio/CSharp/Impl/Snippets/SnippetExpansionClient.cs +++ b/src/VisualStudio/CSharp/Impl/Snippets/SnippetExpansionClient.cs @@ -9,8 +9,7 @@ using System.Threading; using System.Xml.Linq; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.AddImports; -using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Extensions; @@ -24,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; @@ -89,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, CodeGenerationPreferences preferences, 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)); @@ -145,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, preferences, 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 3e030c6f1a6e0..b035db12d94e0 100644 --- a/src/VisualStudio/CSharp/Impl/VSPackage.resx +++ b/src/VisualStudio/CSharp/Impl/VSPackage.resx @@ -189,10 +189,16 @@ 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; -Stack Trace Explorer; +Inheritance Margin; C# Advanced options page keywords diff --git a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf index 7e0a82fdef83a..71a98a3e6778e 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/CSharpVSResources.de.xlf @@ -204,7 +204,7 @@ Insert Snippet - Ausschnitt einfügen + Schnipsel einfügen @@ -614,7 +614,7 @@ Place _code snippets in completion lists - _Codeausschnitte in Vervollständigungslisten anordnen + _Codeschnipsel in Vervollständigungslisten anordnen @@ -764,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/VSPackage.cs.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.cs.xlf index e99b3e0b55a33..ea0c528c96ef2 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.cs.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.cs.xlf @@ -80,61 +80,66 @@ prefer throwing properties; prefer auto properties; regex; regular expression; -Use enhanced colors; -Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; - Underline reassigned variables; -Display inline hints; -Show diagnostics for closed files; -Colorize regular expression; -Highlight related components under cursor; +Colorize regular expressions; +Highlight related components under cursor; Report invalid regular expressions; -Enable full solution analysis; -Perform editor feature analysis in external process; -Enable navigation to decompiled sources; -Using directives; -Place system directives first when sorting usings; -Separate using directive groups; -Suggest usings for types in reference assemblies; -Suggest usings for types in NuGet packages; -Highlighting; -Highlight references to symbol under cursor; -Highlight related keywords under cursor; -Outlining; -Enter outlining mode when files open; -Show procedure line separators; -Show outlining for declaration level constructs; -Show outlining for code level constructs; -Show outlining for comments and preprocessor regions; -Collapse regions when collapsing to definitions; -Fading; -Fade out unused usings; -Fade out unreachable code; -Block Structure Guides; -Show guides for declaration level constructs; -Show guides for code level constructs; -Editor Help; -Generate XML documentation comments for ///; -Insert * at the start of new lines when writing /* */ comments; -Show preview for rename tracking; -Split string literals on Enter; -Report invalid placeholders in string.Format calls; -Extract Method; -Don't put ref or out on custom struct; -Implement Interface or Abstract Class; -When inserting properties, events and methods, place them; -with other members of the same kind; -at the end; -When generating property; -prefer throwing properties; -prefer auto properties; -regex; -regular expression; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; +Inheritance Margin; + Podtrhnout znovu přiřazené proměnné; +Zobrazovat vložené nápovědy; +Zobrazit diagnostiku pro zavřené soubory; +Vybarvit regulární výraz; +Zvýrazňovat související komponenty pod kurzorem; +Nahlásit neplatné regulární výrazy; +Povolit úplnou analýzu řešení; +Provést analýzu funkcí editoru v externím procesu; +Povolit navigaci na dekompilované zdroje; +Direktivy using; +Při řazení direktiv using umístit systémové direktivy jako první; +Oddělovat skupiny direktiv using; +Navrhnout použití typů v sestaveních reference; +Navrhnout použití typů v balíčcích NuGet; +Zvýrazňování; +Zvýrazňovat odkazy na symbol pod kurzorem; +Zvýrazňovat související klíčová slova pod kurzorem; +Sbalení; +Po otevření souborů přejít do režimu osnovy; +Zobrazovat oddělovače řádků procedur; +Zobrazit sbalení pro konstrukty na úrovni deklarace; +Zobrazit sbalení pro konstrukty na úrovni kódu; +Zobrazit sbalení pro komentáře a oblasti pro preprocesor; +Při sbalování na definice sbalovat oblasti; +Zesvětlení; +Zesvětlit nepoužité direktivy using; +Zesvětlit nedosažitelný kód; +Vodítka pro strukturu bloku; +Zobrazit vodítka pro konstrukty na úrovni deklarace; +Zobrazit vodítka pro konstrukty na úrovni kódu; +Nápověda k editoru; +Generovat komentáře dokumentace XML pro ///; +Při psaní komentářů /* */ vkládat na začátek nových řádků hvězdičku (*); +Zobrazovat náhled pro sledování přejmenování; +Rozdělit literály řetězců u Enter; +Oznamovat neplatné zástupné symboly ve voláních string.Format; +Extrahovat metodu; +Nevkládat odkaz nebo výstup do vlastní struktury; +Implementovat rozhraní nebo abstraktní třídu; +Vlastnosti, události a metody při vkládání umístit; +s ostatními členy stejného druhu; +na konec; +Při generování vlastnosti; +preferovat vyvolávací vlastnosti; +preferovat automatické vlastnosti; +reg. výr.; +regulární výraz; +Používat rozšířené barvy; +Barevné schéma editoru; +Okraj dědičnosti C# Advanced options page keywords diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.de.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.de.xlf index 79a4648506fb9..d86915c6f5205 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.de.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.de.xlf @@ -80,61 +80,66 @@ prefer throwing properties; prefer auto properties; regex; regular expression; -Use enhanced colors; -Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; - Underline reassigned variables; -Display inline hints; -Show diagnostics for closed files; -Colorize regular expression; -Highlight related components under cursor; +Colorize regular expressions; +Highlight related components under cursor; Report invalid regular expressions; -Enable full solution analysis; -Perform editor feature analysis in external process; -Enable navigation to decompiled sources; -Using directives; -Place system directives first when sorting usings; -Separate using directive groups; -Suggest usings for types in reference assemblies; -Suggest usings for types in NuGet packages; -Highlighting; -Highlight references to symbol under cursor; -Highlight related keywords under cursor; -Outlining; -Enter outlining mode when files open; -Show procedure line separators; -Show outlining for declaration level constructs; -Show outlining for code level constructs; -Show outlining for comments and preprocessor regions; -Collapse regions when collapsing to definitions; -Fading; -Fade out unused usings; -Fade out unreachable code; -Block Structure Guides; -Show guides for declaration level constructs; -Show guides for code level constructs; -Editor Help; -Generate XML documentation comments for ///; -Insert * at the start of new lines when writing /* */ comments; -Show preview for rename tracking; -Split string literals on Enter; -Report invalid placeholders in string.Format calls; -Extract Method; -Don't put ref or out on custom struct; -Implement Interface or Abstract Class; -When inserting properties, events and methods, place them; -with other members of the same kind; -at the end; -When generating property; -prefer throwing properties; -prefer auto properties; -regex; -regular expression; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; +Inheritance Margin; + Neu zugewiesene Variablen unterstreichen; +Inlinehinweise anzeigen; +Diagnoseinformationen für geschlossene Dateien anzeigen; +Reguläre Ausdrücke farbig hervorheben; +Zugehörige Komponenten unter dem Cursor markieren; +Ungültige reguläre Ausdrücke melden; +Vollständige Lösungsanalyse aktivieren; +Editor-Funktionsanalyse in externem Prozess ausführen; +Navigation zu dekompilierten Quellen aktivieren; +using-Anweisungen; +Systemanweisungen beim Sortieren von using-Anweisungen an erster Stelle platzieren; +Gruppen von using-Anweisungen trennen; +using-Anweisungen für Typen in Verweisassemblys vorschlagen; +using-Anweisungen für Typen in NuGet-Paketen vorschlagen; +Hervorhebung; +Verweise auf Symbol unter Cursor hervorheben; +Verwandte Schlüsselbegriffe unter Cursor anzeigen; +Gliederung; +Gliederungsmodus beim Öffnen von Dateien starten; +Zeilentrennzeichen in Prozeduren anzeigen; +Gliederung für Konstrukte auf Deklarationsebene anzeigen; +Gliederung für Konstrukte auf Codeebene anzeigen; +Gliederung für Kommentare und Präprozessorregionen anzeigen; +Regionen beim Reduzieren auf Definitionen zuklappen; +Ausblenden; +Nicht verwendete using-Anweisungen ausblenden; +Unerreichbaren Code ausblenden; +Führungslinien für Struktur blockieren; +Führungslinien für Konstrukte auf Deklarationsebene anzeigen; +Führungslinien für Konstrukte auf Codeebene anzeigen; +Editor-Hilfe; +XML-Dokumentationskommentare für /// generieren; +Beim Schreiben von Kommentaren (/* */) * am Beginn neuer Zeilen einfügen; +Vorschau für Nachverfolgung beim Umbenennen anzeigen; +Zeichenfolgenliterale bei Eingabe teilen; +Ungültige Platzhalter in string.Format-Aufrufen melden; +Methode extrahieren; +ref oder out nicht in benutzerdefinierte Struktur platzieren; +Schnittstellen- oder abstrakte Klasse implementieren; +Eigenschaften, Ereignisse und Methoden beim Einfügen; +bei anderen Membern derselben Art platzieren; +am Ende platzieren; +Beim Generieren von Eigenschaften; +ausgelöste Eigenschaften bevorzugen; +automatische Eigenschaften bevorzugen; +regex; +regulärer Ausdruck; +Erweiterte Farben verwenden; +Editor-Farbschema; +Vererbungsrand; C# Advanced options page keywords @@ -303,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 89c86e85a86ff..838fa8ea7f5b2 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.es.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.es.xlf @@ -80,61 +80,67 @@ prefer throwing properties; prefer auto properties; regex; regular expression; -Use enhanced colors; -Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; - Underline reassigned variables; -Display inline hints; -Show diagnostics for closed files; -Colorize regular expression; -Highlight related components under cursor; +Colorize regular expressions; +Highlight related components under cursor; Report invalid regular expressions; -Enable full solution analysis; -Perform editor feature analysis in external process; -Enable navigation to decompiled sources; -Using directives; -Place system directives first when sorting usings; -Separate using directive groups; -Suggest usings for types in reference assemblies; -Suggest usings for types in NuGet packages; -Highlighting; -Highlight references to symbol under cursor; -Highlight related keywords under cursor; -Outlining; -Enter outlining mode when files open; -Show procedure line separators; -Show outlining for declaration level constructs; -Show outlining for code level constructs; -Show outlining for comments and preprocessor regions; -Collapse regions when collapsing to definitions; -Fading; -Fade out unused usings; -Fade out unreachable code; -Block Structure Guides; -Show guides for declaration level constructs; -Show guides for code level constructs; -Editor Help; -Generate XML documentation comments for ///; -Insert * at the start of new lines when writing /* */ comments; -Show preview for rename tracking; -Split string literals on Enter; -Report invalid placeholders in string.Format calls; -Extract Method; -Don't put ref or out on custom struct; -Implement Interface or Abstract Class; -When inserting properties, events and methods, place them; -with other members of the same kind; -at the end; -When generating property; -prefer throwing properties; -prefer auto properties; -regex; -regular expression; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; +Inheritance Margin; + Subrayar variables reasignadas; +Mostrar sugerencias insertadas; +Mostrar diagnóstico para archivos cerrados; +Colorear expresión regular; + +Resaltar componentes relacionados bajo el cursor; +Informar sobre expresiones regulares no válidas; +Habilitar análisis de la solución completa; +Realizar el análisis de características del editor en proceso externo; +Habilitar la navegación a orígenes descompilados; +Directivas using; +Poner directivas del sistema primero cuando se organicen instrucciones using; +Separar grupos de directivas using; +Sugerir directivas using para los tipos en los ensamblados de referencia; +Sugerir directivas using para los tipos en los paquetes NuGet; +Resaltar; +Resaltar referencias al símbolo bajo el cursor; +Resaltar palabras clave relacionadas bajo el cursor; +Esquematización; +Especificar el modo de esquematización al abrir los archivos; +Mostrar separadores de líneas de procedimientos; +Mostrar esquematización para construcciones a nivel de declaración; +Mostrar esquematización para construcciones a nivel de código; +Mostrar esquematización para regiones de preprocesador y comentarios; +Contraer regiones cuando se contraigan las definiciones; +Atenuación; +Atenuar directivas using no usadas; +Atenuar código inaccesible; +Guías de estructura de bloque; +Mostrar guías para construcciones a nivel de declaración; +Mostrar guías para construcciones a nivel de código; +Ayuda del editor; +Generar comentarios de documentación XML para ///; +Insertar * al comienzo de las nuevas líneas al escribir comentarios /* */; +Mostrar vista previa para seguimiento de cambio de nombre; +Dividir literales de cadena al presionar Entrar; +Informar sobre marcadores de posición no válidos en llamadas a string.Format; +Extraer método; +No colocar "out" o "ref" en estructura personalizada; +Implementar interfaz o clase abstracta; +Al insertar propiedades, eventos y métodos, colóquelos; +con otros miembros de la misma clase; +al final; +Al generar una propiedad; +preferir propiedades de lanzamiento; +preferir propiedades automáticas; +regex; +expresión regular; +Usar colores mejorados; +Combinación de colores del editor; +Margen de herencia; C# Advanced options page keywords diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.fr.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.fr.xlf index effc18585f42e..02e238087189b 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.fr.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.fr.xlf @@ -80,61 +80,66 @@ prefer throwing properties; prefer auto properties; regex; regular expression; -Use enhanced colors; -Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; - Underline reassigned variables; -Display inline hints; -Show diagnostics for closed files; -Colorize regular expression; -Highlight related components under cursor; +Colorize regular expressions; +Highlight related components under cursor; Report invalid regular expressions; -Enable full solution analysis; -Perform editor feature analysis in external process; -Enable navigation to decompiled sources; -Using directives; -Place system directives first when sorting usings; -Separate using directive groups; -Suggest usings for types in reference assemblies; -Suggest usings for types in NuGet packages; -Highlighting; -Highlight references to symbol under cursor; -Highlight related keywords under cursor; -Outlining; -Enter outlining mode when files open; -Show procedure line separators; -Show outlining for declaration level constructs; -Show outlining for code level constructs; -Show outlining for comments and preprocessor regions; -Collapse regions when collapsing to definitions; -Fading; -Fade out unused usings; -Fade out unreachable code; -Block Structure Guides; -Show guides for declaration level constructs; -Show guides for code level constructs; -Editor Help; -Generate XML documentation comments for ///; -Insert * at the start of new lines when writing /* */ comments; -Show preview for rename tracking; -Split string literals on Enter; -Report invalid placeholders in string.Format calls; -Extract Method; -Don't put ref or out on custom struct; -Implement Interface or Abstract Class; -When inserting properties, events and methods, place them; -with other members of the same kind; -at the end; -When generating property; -prefer throwing properties; -prefer auto properties; -regex; -regular expression; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; +Inheritance Margin; + 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; +Surligner les composants liés sous le curseur; +Signaler les expressions régulières non valides; +Activer l'analyse complète de la solution; +Effectuer l'analyse des fonctionnalités de l'éditeur dans un processus externe; +Activer la navigation vers les sources décompilées; +Directives using; +Placer en premier les directives system au moment du tri des using; +Séparer les groupes de directives using; +Suggérer des using pour les types dans les assemblys de référence; +Suggérer des using pour les types dans les packages NuGet; +Mise en surbrillance; +Mettre en surbrillance les références au symbole sous le curseur; +Mettre en surbrillance les mots clés liés sous le curseur; +Mode Plan; +Passer en mode Plan à l'ouverture des fichiers; +Afficher les séparateurs de ligne de procédure; +Afficher le mode Plan pour les constructions au niveau des déclarations; +Afficher le mode Plan pour les constructions au niveau du code; +Afficher le mode Plan pour les commentaires et les régions du préprocesseur; +Réduire les régions au moment de la réduction aux définitions; +Atténuation; +Atténuer les using inutilisés; +Atténuer le code inaccessible; +Repères de structure de bloc; +Afficher les repères pour les constructions au niveau des déclarations; +Afficher les repères pour les constructions au niveau du code; +Aide de l'éditeur; +Générer des commentaires de documentation XML pour ///; +Insérer * au début des nouvelles lignes pour l'écriture de commentaires /* */; +Afficher un aperçu pour le suivi des renommages; +Diviser les littéraux de chaîne avec Entrée; +Signaler les espaces réservés non valides dans les appels de string.Format; +Extraire la méthode; +Ne pas placer ref ou out dans un struct personnalisé; +Implémenter une interface ou une classe abstraite; +Au moment d'insérer des propriétés, des événements et des méthodes, les placer; +avec d'autres membres du même genre; +à la fin; +Durant la génération de propriétés; +préférer les propriétés de levée d'exceptions; +préférer les propriétés automatiques; +regex; +expression régulière; +Utiliser des couleurs améliorées; +Modèle de couleurs de l'éditeur; +Marge d'héritage; C# Advanced options page keywords diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.it.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.it.xlf index 9153c5f6c2df6..e357fbd6edacb 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.it.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.it.xlf @@ -80,61 +80,66 @@ prefer throwing properties; prefer auto properties; regex; regular expression; -Use enhanced colors; -Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; - Underline reassigned variables; -Display inline hints; -Show diagnostics for closed files; -Colorize regular expression; -Highlight related components under cursor; +Colorize regular expressions; +Highlight related components under cursor; Report invalid regular expressions; -Enable full solution analysis; -Perform editor feature analysis in external process; -Enable navigation to decompiled sources; -Using directives; -Place system directives first when sorting usings; -Separate using directive groups; -Suggest usings for types in reference assemblies; -Suggest usings for types in NuGet packages; -Highlighting; -Highlight references to symbol under cursor; -Highlight related keywords under cursor; -Outlining; -Enter outlining mode when files open; -Show procedure line separators; -Show outlining for declaration level constructs; -Show outlining for code level constructs; -Show outlining for comments and preprocessor regions; -Collapse regions when collapsing to definitions; -Fading; -Fade out unused usings; -Fade out unreachable code; -Block Structure Guides; -Show guides for declaration level constructs; -Show guides for code level constructs; -Editor Help; -Generate XML documentation comments for ///; -Insert * at the start of new lines when writing /* */ comments; -Show preview for rename tracking; -Split string literals on Enter; -Report invalid placeholders in string.Format calls; -Extract Method; -Don't put ref or out on custom struct; -Implement Interface or Abstract Class; -When inserting properties, events and methods, place them; -with other members of the same kind; -at the end; -When generating property; -prefer throwing properties; -prefer auto properties; -regex; -regular expression; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; +Inheritance Margin; + Sottolinea variabili riassegnate; +Visualizza suggerimenti inline; +Mostra diagnostica per file chiusi; +Colora espressione regolare; +Evidenzia i componenti correlati sotto il cursore; +Segnala espressioni regolari non valide; +Abilita analisi della soluzione completa; +Esegui analisi delle funzionalità dell'editor in processo esterno; +Abilita spostamento a origini decompilate; +Direttive using; +Inserisci prima le direttive System durante l'ordinamento delle direttive using; +Separa gruppi di direttive using; +Suggerisci le direttive using per i tipi in assembly di riferimento; +Suggerisci le direttive using per i tipi in pacchetti NuGet; +Evidenziazione; +Evidenzia riferimenti a simbolo sotto il cursore; +Evidenzia parole chiave correlate sotto il cursore; +Struttura; +Attiva modalità struttura all'apertura del file; +Mostra separatori di riga routine; +Mostra la struttura per i costrutti a livello di dichiarazione; +Mostra la struttura per i costrutti a livello di codice; +Mostra la struttura per i commenti e le aree del preprocessore; +Comprimi regioni durante la compressione delle definizioni; +Dissolvenza; +Applica dissolvenza a direttive using non usate; +Applica dissolvenza a codice non eseguibile; +Guide per strutture a blocchi; +Mostra le guide per i costrutti a livello di dichiarazione; +Mostra le guide per i costrutti a livello di codice; +Guida dell'editor; +Genera commenti relativi alla documentazione XML per ///; +Inserisci * all'inizio di nuove righe quando si scrivono commenti /* */; +Mostra anteprima per verifica ridenominazione; +Dividi valori letterali stringa dopo INVIO; +Segnala segnaposto non validi in chiamate string.Format; +Estrai metodo; +Non inserire out o ref in struct personalizzata; +Implementa interfaccia o classe astratta; +Posiziona proprietà, eventi e metodi inseriti; +con altri membri dello stesso tipo; +alla fine; +Durante la generazione della proprietà; +preferisci proprietà generate; +preferisci proprietà automatiche; +regex; +espressione regolare; +Usa colori migliorati; +Combinazione colori editor; +Margine di ereditarietà; C# Advanced options page keywords diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ja.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ja.xlf index 7a7cd70b7a457..a79805c1e476e 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ja.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ja.xlf @@ -80,61 +80,66 @@ prefer throwing properties; prefer auto properties; regex; regular expression; -Use enhanced colors; -Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; - Underline reassigned variables; -Display inline hints; -Show diagnostics for closed files; -Colorize regular expression; -Highlight related components under cursor; +Colorize regular expressions; +Highlight related components under cursor; Report invalid regular expressions; -Enable full solution analysis; -Perform editor feature analysis in external process; -Enable navigation to decompiled sources; -Using directives; -Place system directives first when sorting usings; -Separate using directive groups; -Suggest usings for types in reference assemblies; -Suggest usings for types in NuGet packages; -Highlighting; -Highlight references to symbol under cursor; -Highlight related keywords under cursor; -Outlining; -Enter outlining mode when files open; -Show procedure line separators; -Show outlining for declaration level constructs; -Show outlining for code level constructs; -Show outlining for comments and preprocessor regions; -Collapse regions when collapsing to definitions; -Fading; -Fade out unused usings; -Fade out unreachable code; -Block Structure Guides; -Show guides for declaration level constructs; -Show guides for code level constructs; -Editor Help; -Generate XML documentation comments for ///; -Insert * at the start of new lines when writing /* */ comments; -Show preview for rename tracking; -Split string literals on Enter; -Report invalid placeholders in string.Format calls; -Extract Method; -Don't put ref or out on custom struct; -Implement Interface or Abstract Class; -When inserting properties, events and methods, place them; -with other members of the same kind; -at the end; -When generating property; -prefer throwing properties; -prefer auto properties; -regex; -regular expression; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; +Inheritance Margin; + 再割り当てされる変数に下線を引く; +インラインのヒントを表示する; +閉じているファイルの診断結果を表示する; +正規表現をカラー化する; +カーソルの下にある関連コンポーネントを強調表示する; +無効な正規表現を報告する; +完全ソリューション解析を有効にする; +外部プロセスでエディター機能解析を実行する; +逆コンパイルされたソースへのナビゲーションを有効にする; +ディレクティブを使用する; +using を並べ替える際に、system ディレクティブを先頭に配置する; +using ディレクティブ グループを分離する; +参照アセンブリの型に using を提案する; +NuGet パッケージの型に using を提案する; +強調表示; +カーソルの下にあるシンボルへの参照を強調表示する; +カーソルの下にある関連キーワードを強調表示する; +アウトライン; +ファイルを開くときにアウトライン モードに入る; +プロシージャ行の区切り記号を表示する; +宣言レベルのコンストラクトのアウトラインを表示する; +コード レベルのコンストラクトのアウトラインを表示する; +コメントとプリプロセッサ領域のアウトラインを表示する; +定義を折りたたむときに regions を折りたたむ; +フェード; +未使用の using をフェードアウトする; +到達できないコードをフェードアウトする; +ブロック構造のガイド; +宣言レベルのコンストラクトのガイドを表示する; +コード レベルのコンストラクトのガイドを表示する; +エディターのヘルプ; +/// が入力されたとき、XML ドキュメント コメントを生成する; +/* */ コメントを記述する際、新しい行の先頭に * を挿入する; +名前変更追跡のプレビューを表示する; +Enter で文字列リテラルを分割する; +string.Format の呼び出しで無効なプレースホルダーをレポートする; +メソッドを抽出する; +カスタム構造体に ref または out を設定しない; +インターフェイスまたは抽象クラスを実装する; +プロパティ、イベント、メソッドを挿入する際には、次の場所に挿入する; +同じ種類の他のメンバーと共に; +末尾; +プロパティの生成時; +スロー プロパティを優先する; +自動プロパティを優先する; +RegEx; +正規表現; +拡張された色を使用する; +エディターの配色; +継承余白; C# Advanced options page keywords diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ko.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ko.xlf index e8bc8c2816960..e1db2b0f103f6 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ko.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ko.xlf @@ -80,61 +80,66 @@ prefer throwing properties; prefer auto properties; regex; regular expression; -Use enhanced colors; -Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; - Underline reassigned variables; -Display inline hints; -Show diagnostics for closed files; -Colorize regular expression; -Highlight related components under cursor; +Colorize regular expressions; +Highlight related components under cursor; Report invalid regular expressions; -Enable full solution analysis; -Perform editor feature analysis in external process; -Enable navigation to decompiled sources; -Using directives; -Place system directives first when sorting usings; -Separate using directive groups; -Suggest usings for types in reference assemblies; -Suggest usings for types in NuGet packages; -Highlighting; -Highlight references to symbol under cursor; -Highlight related keywords under cursor; -Outlining; -Enter outlining mode when files open; -Show procedure line separators; -Show outlining for declaration level constructs; -Show outlining for code level constructs; -Show outlining for comments and preprocessor regions; -Collapse regions when collapsing to definitions; -Fading; -Fade out unused usings; -Fade out unreachable code; -Block Structure Guides; -Show guides for declaration level constructs; -Show guides for code level constructs; -Editor Help; -Generate XML documentation comments for ///; -Insert * at the start of new lines when writing /* */ comments; -Show preview for rename tracking; -Split string literals on Enter; -Report invalid placeholders in string.Format calls; -Extract Method; -Don't put ref or out on custom struct; -Implement Interface or Abstract Class; -When inserting properties, events and methods, place them; -with other members of the same kind; -at the end; -When generating property; -prefer throwing properties; -prefer auto properties; -regex; -regular expression; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; +Inheritance Margin; + 다시 할당된 변수에 밑줄 긋기; +인라인 힌트 표시; +닫힌 파일에 대한 진단 표시; +정규식 색 지정; +커서 아래의 관련 구성 요소 강조 표시; +잘못된 정규식 보고; +전체 솔루션 분석 사용; +외부 프로세스에서 편집기 기능 분석 수행; +디컴파일된 소스 탐색 사용; +Using 지시문; +using 정렬 시 system 지시문 먼저 배치; +using 지시문 그룹 구분; +참조 어셈블리의 형식에 using 제안; +NuGet 패키지의 형식에 using 제안; +강조 표시; +커서 아래의 기호에 대한 참조 강조 표시; +커서 아래의 관련 키워드 강조 표시; +개요; +개요 모드로 파일 열기; +프로시저 줄 구분선 표시; +선언 수준 구문에 대한 개요 표시; +코드 수준 구문에 대한 개요 표시; +설명 및 전처리기 영역에 대한 개요 표시; +정의로 축소할 때 영역 축소; +페이딩; +사용하지 않는 using 페이드 아웃; +접근할 수 없는 코드 페이드 아웃; +블록 구조 가이드; +선언 수준 구조에 대한 가이드 표시; +코드 수준 구조에 대한 가이드 표시; +편집기 도움말; +///에 대해 XML 문서 주석 생성; +/* */ 주석을 작성할 때 새 줄의 시작 부분에 * 삽입; +이름 바꾸기 추적 미리 보기 표시; +<Enter> 키를 누르면 문자열 리터럴 분할; +string.Format 호출에서 잘못된 자리 표시자 보고; +메서드 추출; +사용자 지정 구조체에 ref 또는 out 추가 안 함; +인터페이스 또는 추상 클래스 구현; +속성, 이벤트 및 메서드 삽입 시 다음과 같이 배치; +같은 종류의 다른 멤버와 함께; +끝에; +속성 생성 시; +throw되는 속성 선호; +자동 속성 선호; +regex; +정규식; +향상된 색 사용; +편집기 색 구성표; +상속 여백; C# Advanced options page keywords diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pl.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pl.xlf index f1a9527addbad..7f70614c687f8 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pl.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pl.xlf @@ -80,61 +80,66 @@ prefer throwing properties; prefer auto properties; regex; regular expression; -Use enhanced colors; -Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; - Underline reassigned variables; -Display inline hints; -Show diagnostics for closed files; -Colorize regular expression; -Highlight related components under cursor; +Colorize regular expressions; +Highlight related components under cursor; Report invalid regular expressions; -Enable full solution analysis; -Perform editor feature analysis in external process; -Enable navigation to decompiled sources; -Using directives; -Place system directives first when sorting usings; -Separate using directive groups; -Suggest usings for types in reference assemblies; -Suggest usings for types in NuGet packages; -Highlighting; -Highlight references to symbol under cursor; -Highlight related keywords under cursor; -Outlining; -Enter outlining mode when files open; -Show procedure line separators; -Show outlining for declaration level constructs; -Show outlining for code level constructs; -Show outlining for comments and preprocessor regions; -Collapse regions when collapsing to definitions; -Fading; -Fade out unused usings; -Fade out unreachable code; -Block Structure Guides; -Show guides for declaration level constructs; -Show guides for code level constructs; -Editor Help; -Generate XML documentation comments for ///; -Insert * at the start of new lines when writing /* */ comments; -Show preview for rename tracking; -Split string literals on Enter; -Report invalid placeholders in string.Format calls; -Extract Method; -Don't put ref or out on custom struct; -Implement Interface or Abstract Class; -When inserting properties, events and methods, place them; -with other members of the same kind; -at the end; -When generating property; -prefer throwing properties; -prefer auto properties; -regex; -regular expression; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; +Inheritance Margin; + Podkreślaj ponownie przypisane zmienne; +Wyświetlaj wskazówki w tekście; +Pokaż dane diagnostyczne dla zamkniętych plików; +Koloruj wyrażenia regularne; +Wyróżnij powiązane składniki pod kursorem; +Raportuj nieprawidłowe wyrażenia regularne; +Włącz pełną analizę rozwiązania; +Wykonaj analizę funkcji edytora w procesie zewnętrznym; +Włącz nawigowanie do dekompilowanych źródeł; +Dyrektywy using; +Umieść najpierw dyrektywy system podczas sortowania deklaracji using; +Oddziel grupy dyrektywy using; +Sugeruj dyrektywy using dla typów w zestawach odwołania; +Sugeruj dyrektywy using dla typów w pakietach NuGet; +Wyróżnianie; +Wyróżnij odwołania do symbolu wskazanego przez kursor; +Wyróżnij pokrewne słowa kluczowe wskazane przez kursor; +Konspekt; +Przejdź do trybu konspektu przy otwieraniu plików; +Pokaż separatory wierszy procedury; +Pokaż konspekt dla konstrukcji na poziomie deklaracji; +Pokaż konspekt dla konstrukcji na poziomie kodu; +Pokaż konspekt dla regionów komentarzy i preprocesora; +Zwiń regiony podczas zwijania do definicji; +Zanikanie; +Zanikanie nieużywanych dyrektyw using; +Zanikanie nieosiągalnego kodu; +Prowadnice struktury blokowej; +Pokaż prowadnice dla konstrukcji na poziomie deklaracji; +Pokaż prowadnice dla konstrukcji na poziomie kodu; +Pomoc edytora; +Generuj komentarze dokumentacji XML dla elementów ///; +Wstaw znak * na początku nowych wierszy podczas pisania komentarzy typu /* */; +Pokaż podgląd śledzenia zmian nazw; +Dziel literały ciągów po naciśnięciu klawisza Enter; +Zgłaszaj nieprawidłowe symbole zastępcze w ciągu.Formatuj komórki; +Metoda wyodrębniania; +Nie umieszczaj parametrów ref i out w strukturze niestandardowej; +Implementuj interfejs lub klasę abstrakcyjną; +W przypadku wstawiania właściwości, zdarzeń i metod umieszczaj je; +razem z innymi składowymi tego samego rodzaju; +na końcu; +Podczas generowania właściwości; +preferuj zgłaszanie właściwości; +preferuj właściwości automatyczne; +wyrażenie regularne; +wyrażenie regularne; +Użyj ulepszonych kolorów; +Schemat kolorów edytora; +Margines dziedziczenia C# Advanced options page keywords diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pt-BR.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pt-BR.xlf index 40399cdcb1c59..0d96999463fd3 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pt-BR.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.pt-BR.xlf @@ -80,61 +80,66 @@ prefer throwing properties; prefer auto properties; regex; regular expression; -Use enhanced colors; -Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; - Underline reassigned variables; -Display inline hints; -Show diagnostics for closed files; -Colorize regular expression; -Highlight related components under cursor; +Colorize regular expressions; +Highlight related components under cursor; Report invalid regular expressions; -Enable full solution analysis; -Perform editor feature analysis in external process; -Enable navigation to decompiled sources; -Using directives; -Place system directives first when sorting usings; -Separate using directive groups; -Suggest usings for types in reference assemblies; -Suggest usings for types in NuGet packages; -Highlighting; -Highlight references to symbol under cursor; -Highlight related keywords under cursor; -Outlining; -Enter outlining mode when files open; -Show procedure line separators; -Show outlining for declaration level constructs; -Show outlining for code level constructs; -Show outlining for comments and preprocessor regions; -Collapse regions when collapsing to definitions; -Fading; -Fade out unused usings; -Fade out unreachable code; -Block Structure Guides; -Show guides for declaration level constructs; -Show guides for code level constructs; -Editor Help; -Generate XML documentation comments for ///; -Insert * at the start of new lines when writing /* */ comments; -Show preview for rename tracking; -Split string literals on Enter; -Report invalid placeholders in string.Format calls; -Extract Method; -Don't put ref or out on custom struct; -Implement Interface or Abstract Class; -When inserting properties, events and methods, place them; -with other members of the same kind; -at the end; -When generating property; -prefer throwing properties; -prefer auto properties; -regex; -regular expression; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; +Inheritance Margin; + Variáveis reatribuídas de sublinhado; +Exibir as dicas embutidas; +Mostrar os diagnósticos de arquivos fechados; +Colorir a expressão regular; +Realçar os componentes relacionados sob o cursor; +Relatar as expressões regulares inválidas; +Habilitar a análise completa da solução; +Executar a análise de recurso do editor em processo externo; +Habilitar a navegação para fontes decompiladas; +Diretivas using; +Colocar as diretivas do sistema primeiro ao classificar usings; +Separar grupos de diretivas using; +Sugerir usings para tipos em assemblies de referência; +Sugerir usings para tipos em pacotes NuGet; +Realce; +Realçar as referências ao símbolo sob o cursor +;Realçar as palavras-chave relacionadas sob o cursor; +Estrutura de tópicos; +Entrar no modo de estrutura de tópicos quando os arquivos são abertos; +Mostrar separadores de linha de procedimento; +Mostrar a estrutura de tópicos para constructos no nível da declaração; +Mostrar a estrutura de tópicos para constructos no nível do código; +Mostrar a estrutura de tópicos para comentários e regiões de pré-processador; +Recolher as regiões ao recolher as definições; +Esmaecimento; +Esmaecer as usings não usadas; +Esmaecer o código inacessível; +Bloquear as Guias de Estrutura; +Mostrar as guias de constructos no nível da declaração; +Mostrar as guias de constructos no nível do código; +Ajuda do Editor; +Gerar comentários da documentação XML para ///; +Inserir * no início de novas linhas ao escrever comentários de /* */; +Mostrar a visualização para acompanhamento de renomeação; +Dividir os literais de cadeia de caracteres ao pressionar Enter; +Relatar os espaços reservados inválidos nas chamadas a string.Format; +Extrair o Método; +Não colocar ref nem out no struct personalizado; +Implementar a Classe de Interface ou Abstrata; +Ao inserir propriedades, eventos e métodos, colocá-los; +com outros membros do mesmo tipo; +no fim; +Ao gerar uma propriedade; +preferir propriedades de lançamento; +preferir propriedades automáticas; +regex; +expressão regular; +Usar cores avançadas; +Esquema de Cores do Editor; +Margem de herança; C# Advanced options page keywords diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ru.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ru.xlf index b60ddd9b1bc6f..b8e7d76be8d13 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ru.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.ru.xlf @@ -80,61 +80,66 @@ prefer throwing properties; prefer auto properties; regex; regular expression; -Use enhanced colors; -Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; - Underline reassigned variables; -Display inline hints; -Show diagnostics for closed files; -Colorize regular expression; -Highlight related components under cursor; +Colorize regular expressions; +Highlight related components under cursor; Report invalid regular expressions; -Enable full solution analysis; -Perform editor feature analysis in external process; -Enable navigation to decompiled sources; -Using directives; -Place system directives first when sorting usings; -Separate using directive groups; -Suggest usings for types in reference assemblies; -Suggest usings for types in NuGet packages; -Highlighting; -Highlight references to symbol under cursor; -Highlight related keywords under cursor; -Outlining; -Enter outlining mode when files open; -Show procedure line separators; -Show outlining for declaration level constructs; -Show outlining for code level constructs; -Show outlining for comments and preprocessor regions; -Collapse regions when collapsing to definitions; -Fading; -Fade out unused usings; -Fade out unreachable code; -Block Structure Guides; -Show guides for declaration level constructs; -Show guides for code level constructs; -Editor Help; -Generate XML documentation comments for ///; -Insert * at the start of new lines when writing /* */ comments; -Show preview for rename tracking; -Split string literals on Enter; -Report invalid placeholders in string.Format calls; -Extract Method; -Don't put ref or out on custom struct; -Implement Interface or Abstract Class; -When inserting properties, events and methods, place them; -with other members of the same kind; -at the end; -When generating property; -prefer throwing properties; -prefer auto properties; -regex; -regular expression; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; +Inheritance Margin; + Подчеркивать переназначенные переменные; +Показывать встроенные подсказки; +Показывать диагностику для закрытых файлов; +Выделять регулярные выражения; +Выделять родственные компоненты под курсором; +Сообщать о недопустимых регулярных выражениях; +Включить полный анализ решения; +Выполнять анализ функций редактора во внешнем процессе; +Включить переход к декомпилированным источникам; +Директивы using; +Располагать директивы system первыми при сортировке директив using; +Разделять группы директив using; +Предлагать директивы using для типов в базовых сборках; +Предлагать директивы using для типов в пакетах NuGet; +Выделение; +Выделять ссылки на символ под курсором; +Выделять родственные ключевые слова под курсором; +Структурирование; +Включать режим редактирования структуры при открытии файлов; +Показывать разделители строк процедур; +Показывать структуру для конструкций уровня объявления; +Показывать структуру для конструкций уровня кода; +Показывать структуру для комментариев и областей препроцессора; +Сворачивать области при сворачивании в определения; +Показывать бледным цветом; +Показывать неиспользуемые директивы using бледным цветом; +Показывать недостижимый код бледным цветом; +Направляющие для структуры блоков; +Показывать направляющие для конструкций уровня объявления; +Показывать направляющие для конструкций уровня кода; +Справка по редактору; +Генерировать комментарии XML-документации для ///; +Вставлять "*" в начале новой строки при написании комментариев типа "/* */"; +Показывать предварительный просмотр для отслеживания переименований; +Разделять строковые литералы при нажатии клавиши ВВОД; +Сообщать о недопустимых заполнителях в вызовах string.Format; +Извлечение метода; +Не помещать ref и out в пользовательские структуры; +Реализовать интерфейс или абстрактный класс; +При вставке свойств, методов и событий помещать их +вместе с другими элементами того же типа +в конец; +При создании свойства +предпочитать свойства, создающие исключения; +предпочитать автоматические свойства; +регулярное выражение; +регулярное выражение; +Использовать расширенный набор цветов; +Цветовая схема редактора; +Поле наследования; C# Advanced options page keywords diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.tr.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.tr.xlf index a71a513086523..f0a7f6d677616 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.tr.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.tr.xlf @@ -80,61 +80,66 @@ prefer throwing properties; prefer auto properties; regex; regular expression; -Use enhanced colors; -Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; - Underline reassigned variables; -Display inline hints; -Show diagnostics for closed files; -Colorize regular expression; -Highlight related components under cursor; +Colorize regular expressions; +Highlight related components under cursor; Report invalid regular expressions; -Enable full solution analysis; -Perform editor feature analysis in external process; -Enable navigation to decompiled sources; -Using directives; -Place system directives first when sorting usings; -Separate using directive groups; -Suggest usings for types in reference assemblies; -Suggest usings for types in NuGet packages; -Highlighting; -Highlight references to symbol under cursor; -Highlight related keywords under cursor; -Outlining; -Enter outlining mode when files open; -Show procedure line separators; -Show outlining for declaration level constructs; -Show outlining for code level constructs; -Show outlining for comments and preprocessor regions; -Collapse regions when collapsing to definitions; -Fading; -Fade out unused usings; -Fade out unreachable code; -Block Structure Guides; -Show guides for declaration level constructs; -Show guides for code level constructs; -Editor Help; -Generate XML documentation comments for ///; -Insert * at the start of new lines when writing /* */ comments; -Show preview for rename tracking; -Split string literals on Enter; -Report invalid placeholders in string.Format calls; -Extract Method; -Don't put ref or out on custom struct; -Implement Interface or Abstract Class; -When inserting properties, events and methods, place them; -with other members of the same kind; -at the end; -When generating property; -prefer throwing properties; -prefer auto properties; -regex; -regular expression; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; +Inheritance Margin; + 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; +İmlecin altındaki ilgili bileşenleri vurgula; +Geçersiz normal ifadeleri bildir; +Tam çözüm analizini etkinleştir; +Dış işlemde düzenleyici özellik analizi gerçekleştir; +Kaynak koda dönüştürülen kaynaklar için gezintiyi etkinleştir; +Using yönergeleri; +Using yönergelerini sıralarken sistem yönergelerini en başa yerleştir; +Using yönerge gruplarını ayır; +Başvuru bütünleştirilmiş kodlarında türler için using yönergeleri öner; +NuGet paketlerinde türler için using yönergeleri öner; +Vurgulama; +İmlecin altındaki sembole yönelik başvuruları vurgula; +İmlecin altındaki ilgili anahtar sözcükleri vurgula; +Ana Hat Oluşturma; +Dosyalar açılırken ana hat oluşturma moduna gir; +Yordam satır ayırıcılarını göster; +Bildirim düzeyinde yapılar için ana hattı göster; +Kod düzeyinde yapılar için ana hattı göster; +Açıklamalar ve ön işlemci bölgeleri için ana hattı göster; +Tanımlara daraltırken bölgeleri daralt; +Soluklaştırma; +Kullanılmayan using deyimlerini soluklaştır; +Erişilemeyen kodu soluklaştır; +Blok Yapısı Kılavuzları; +Bildirim düzeyinde yapılar için kılavuzları göster; +Kod düzeyinde yapılar için kılavuzları göster; +Düzenleyici Yardımı; +/// için XML belge açıklamaları oluştur; +/* */ açıklamaları yazılırken her yeni satırın başına * ekle; +Yeniden adlandırma izlemesi için önizleme göster; +Enter tuşuna basıldığında dize sabit değerlerini böl; +string.Format çağrılarındaki geçersiz yer tutucuları bildir; +Ayıklama Metodu; +Özel yapıya ref veya out koyma; +Arabirim veya Soyut Sınıfı uygula; +Özellik, olay ve metot eklerken bunları; +aynı türdeki başka üyelerle birlikte; +sona yerleştir; +Özellik oluştururken; +özel durum oluşturan özellikleri tercih et; +otomatik özellikleri tercih et; +normal ifade; +normal ifade; +Gelişmiş renkleri kullan; +Düzenleyici Renk Düzeni; +İçe Aktarma Kenar Boşluğu; C# Advanced options page keywords diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hans.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hans.xlf index eae7dfb6b3f7d..0448bfe7e4d14 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hans.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hans.xlf @@ -80,61 +80,66 @@ prefer throwing properties; prefer auto properties; regex; regular expression; -Use enhanced colors; -Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; - Underline reassigned variables; -Display inline hints; -Show diagnostics for closed files; -Colorize regular expression; -Highlight related components under cursor; +Colorize regular expressions; +Highlight related components under cursor; Report invalid regular expressions; -Enable full solution analysis; -Perform editor feature analysis in external process; -Enable navigation to decompiled sources; -Using directives; -Place system directives first when sorting usings; -Separate using directive groups; -Suggest usings for types in reference assemblies; -Suggest usings for types in NuGet packages; -Highlighting; -Highlight references to symbol under cursor; -Highlight related keywords under cursor; -Outlining; -Enter outlining mode when files open; -Show procedure line separators; -Show outlining for declaration level constructs; -Show outlining for code level constructs; -Show outlining for comments and preprocessor regions; -Collapse regions when collapsing to definitions; -Fading; -Fade out unused usings; -Fade out unreachable code; -Block Structure Guides; -Show guides for declaration level constructs; -Show guides for code level constructs; -Editor Help; -Generate XML documentation comments for ///; -Insert * at the start of new lines when writing /* */ comments; -Show preview for rename tracking; -Split string literals on Enter; -Report invalid placeholders in string.Format calls; -Extract Method; -Don't put ref or out on custom struct; -Implement Interface or Abstract Class; -When inserting properties, events and methods, place them; -with other members of the same kind; -at the end; -When generating property; -prefer throwing properties; -prefer auto properties; -regex; -regular expression; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; +Inheritance Margin; + 为重新分配变量添加下划线; +显示内联提示; +显示对已关闭文件的诊断; +对正则表达式着色; +突出显示游标下的相关组件; +报告无效的正则表达式; +启用完整解决方案分析; +在外部进程中执行编辑器功能分析; +对反编译的源启用导航; +Using 指令; +对 using 进行排序时将系统指令放在开头; +将 using 指令组分隔开来; +建议对引用程序集中的类型使用 using; +建议对 NuGet 包中的类型使用 using; +突出显示; +突出显示对游标下的符号的引用; +突出显示游标下的相关关键字; +大纲; +在文件打开时输入大纲模式; +显示流程行分隔符; +显示声明级别构造的大纲; +显示代码级别构造的大纲; +显示注释和预处理器区域的大纲; +在折叠到定义时折叠区域; +淡出; +未使用的 using 淡出; +不可访问的代码淡出; +块结构指南; +显示声明级别构造的指南; +显示代码级别构造的指南; +编辑器帮助; +为 /// 生成 XML 文档注释; +在写入 /* */ 注释时在新行开头插入 *; +显示重命名跟踪的预览; +在按 Enter 时拆分字符串文本; +报告 string.Format 调用中的无效占位符; +提取方法; +不要在自定义结构上放置 ref 或 out; +实现接口或抽象类; +插入属性、事件和方法时,放置它们; +具有相同类型的其他成员; +位于末尾; +在生成属性时; +首选引发属性; +首选自动属性; +regex; +正则表达式; +使用增强色; +编辑器配色方案; +继承边距; C# Advanced options page keywords diff --git a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hant.xlf b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hant.xlf index 5302673a1260a..827eab510dd75 100644 --- a/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hant.xlf +++ b/src/VisualStudio/CSharp/Impl/xlf/VSPackage.zh-Hant.xlf @@ -80,61 +80,66 @@ prefer throwing properties; prefer auto properties; regex; regular expression; -Use enhanced colors; -Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; - Underline reassigned variables; -Display inline hints; -Show diagnostics for closed files; -Colorize regular expression; -Highlight related components under cursor; +Colorize regular expressions; +Highlight related components under cursor; Report invalid regular expressions; -Enable full solution analysis; -Perform editor feature analysis in external process; -Enable navigation to decompiled sources; -Using directives; -Place system directives first when sorting usings; -Separate using directive groups; -Suggest usings for types in reference assemblies; -Suggest usings for types in NuGet packages; -Highlighting; -Highlight references to symbol under cursor; -Highlight related keywords under cursor; -Outlining; -Enter outlining mode when files open; -Show procedure line separators; -Show outlining for declaration level constructs; -Show outlining for code level constructs; -Show outlining for comments and preprocessor regions; -Collapse regions when collapsing to definitions; -Fading; -Fade out unused usings; -Fade out unreachable code; -Block Structure Guides; -Show guides for declaration level constructs; -Show guides for code level constructs; -Editor Help; -Generate XML documentation comments for ///; -Insert * at the start of new lines when writing /* */ comments; -Show preview for rename tracking; -Split string literals on Enter; -Report invalid placeholders in string.Format calls; -Extract Method; -Don't put ref or out on custom struct; -Implement Interface or Abstract Class; -When inserting properties, events and methods, place them; -with other members of the same kind; -at the end; -When generating property; -prefer throwing properties; -prefer auto properties; -regex; -regular expression; +JSON; +Colorize JSON strings; +Report invalid JSON strings; +Detect and offer editor features for JSON strings; Use enhanced colors; Editor Color Scheme; -Inheritance Margin; -Stack Trace Explorer; +Inheritance Margin; + 為重新指派的變數加上底線; +顯示內嵌提示; +顯示已關閉檔案的診斷; +為規則運算式添加色彩; +醒目提示游標下的相關元件; +回報無效的規則運算式; +啟用完整解決方案分析; +在外部處理序中執行編輯器功能分析; +啟用瀏覽至反向組譯的來源; +using 指示詞; +排序使 using 先放置系統指示詞; +分隔 using 指示詞群組; +為參考組件中的類型建議 using; +為 NuGet 套件中的類型建議 using; +醒目提示; +醒目提示游標下的符號參考; +醒目提示游標下的相關關鍵字; +大綱; +在檔案開啟時進入大綱模式; +顯示程序行分隔符號; +顯示宣告層級建構的大綱; +顯示程式碼層級建構的大綱; +顯示註解與前置處理器區域的大綱; +在摺疊到定義時摺疊區域; +漸層; +淡出未使用的 using; +淡出無法執行到的程式碼; +區塊結構輔助線; +顯示宣告層級建構的輔助線; +顯示程式碼層級建構的輔助線; +編輯器說明; +產生 /// 的 XML 文件註解; +在撰寫 /* */ 註解時,於新行開頭插入 *; +顯示重新命名追蹤的預覽; +在按 Enter 鍵時分割字串常值; +回報 string.Format 呼叫中無效的預留位置; +擷取方法; +不要在自訂結構上放置 ref 或 out; +實作介面或抽象類別; +在插入屬性、事件和方法時,予以放置; +隨同其他同種類的成員; +結尾處; +產生屬性時; +建議使用擲回屬性; +建議使用自動屬性; +regex; +規則運算式; +使用進階色彩; +編輯器色彩配置; +繼承頁面邊界 C# Advanced options page keywords 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/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.SettingsEntriesSnapshot.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.SettingsEntriesSnapshot.cs index d81eb99f7002c..52e2619e011ac 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.SettingsEntriesSnapshot.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Analyzers/ViewModel/AnalyzerSettingsViewModel.SettingsEntriesSnapshot.cs @@ -36,7 +36,7 @@ protected override bool TryGetValue(AnalyzerSetting result, string keyName, out return content is not null; } - private string? GetLocationString(SettingLocation location) + private static string? GetLocationString(SettingLocation location) { return location.LocationKind switch { diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.SettingsEntriesSnapshot.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.SettingsEntriesSnapshot.cs index ddd196515217c..00f22a57c2a0e 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.SettingsEntriesSnapshot.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/CodeStyle/ViewModel/CodeStyleSettingsViewModel.SettingsEntriesSnapshot.cs @@ -30,7 +30,7 @@ protected override bool TryGetValue(CodeStyleSetting result, string keyName, out return content is not null; } - private string? GetLocationString(SettingLocation location) + private static string? GetLocationString(SettingLocation location) { return location.LocationKind switch { diff --git a/src/VisualStudio/Core/Def/EditorConfigSettings/Whitespace/ViewModel/WhitespaceViewModel.SettingsEntriesSnapshot.cs b/src/VisualStudio/Core/Def/EditorConfigSettings/Whitespace/ViewModel/WhitespaceViewModel.SettingsEntriesSnapshot.cs index f27e60535f55d..37400e76a305a 100644 --- a/src/VisualStudio/Core/Def/EditorConfigSettings/Whitespace/ViewModel/WhitespaceViewModel.SettingsEntriesSnapshot.cs +++ b/src/VisualStudio/Core/Def/EditorConfigSettings/Whitespace/ViewModel/WhitespaceViewModel.SettingsEntriesSnapshot.cs @@ -29,7 +29,7 @@ protected override bool TryGetValue(WhitespaceSetting result, string keyName, ou return content is not null; } - private string? GetLocationString(SettingLocation location) + private static string? GetLocationString(SettingLocation location) { return location.LocationKind switch { diff --git a/src/VisualStudio/Core/Def/HACK_ThemeColorFixer.cs b/src/VisualStudio/Core/Def/HACK_ThemeColorFixer.cs index 9aecb4b470be2..ed93605b5e1d2 100644 --- a/src/VisualStudio/Core/Def/HACK_ThemeColorFixer.cs +++ b/src/VisualStudio/Core/Def/HACK_ThemeColorFixer.cs @@ -90,6 +90,17 @@ private void UpdateForegroundColors( UpdateForegroundColor(ClassificationTypeNames.RegexOtherEscape, sourceFormatMap, targetFormatMap); UpdateForegroundColor(ClassificationTypeNames.RegexSelfEscapedCharacter, sourceFormatMap, targetFormatMap); + UpdateForegroundColor(ClassificationTypeNames.JsonComment, sourceFormatMap, targetFormatMap); + UpdateForegroundColor(ClassificationTypeNames.JsonNumber, sourceFormatMap, targetFormatMap); + UpdateForegroundColor(ClassificationTypeNames.JsonString, sourceFormatMap, targetFormatMap); + UpdateForegroundColor(ClassificationTypeNames.JsonKeyword, sourceFormatMap, targetFormatMap); + UpdateForegroundColor(ClassificationTypeNames.JsonText, sourceFormatMap, targetFormatMap); + UpdateForegroundColor(ClassificationTypeNames.JsonOperator, sourceFormatMap, targetFormatMap); + UpdateForegroundColor(ClassificationTypeNames.JsonArray, sourceFormatMap, targetFormatMap); + UpdateForegroundColor(ClassificationTypeNames.JsonObject, sourceFormatMap, targetFormatMap); + UpdateForegroundColor(ClassificationTypeNames.JsonPropertyName, sourceFormatMap, targetFormatMap); + UpdateForegroundColor(ClassificationTypeNames.JsonConstructorName, sourceFormatMap, targetFormatMap); + UpdateForegroundColor(ClassificationTypeNames.PreprocessorKeyword, sourceFormatMap, targetFormatMap); UpdateForegroundColor(ClassificationTypeNames.PreprocessorText, sourceFormatMap, targetFormatMap); diff --git a/src/VisualStudio/Core/Def/Implementation/AbstractEditorFactory.cs b/src/VisualStudio/Core/Def/Implementation/AbstractEditorFactory.cs index 547c6fa76bff8..90c281549b465 100644 --- a/src/VisualStudio/Core/Def/Implementation/AbstractEditorFactory.cs +++ b/src/VisualStudio/Core/Def/Implementation/AbstractEditorFactory.cs @@ -336,7 +336,7 @@ private async Task FormatDocumentCreatedFromTemplateAsync(IVsHierarchy hierarchy var formattedText = formattedRoot.GetText(unformattedText.Encoding, unformattedText.ChecksumAlgorithm); // Ensure the line endings are normalized. The formatter doesn't touch everything if it doesn't need to. - var targetLineEnding = formattingOptions.GetOption(FormattingOptions2.NewLine)!; + var targetLineEnding = formattingOptions.NewLine; var originalText = formattedText; foreach (var originalLine in originalText.Lines) diff --git a/src/VisualStudio/Core/Def/Implementation/AnalyzerDependency/AnalyzerFileWatcherService.cs b/src/VisualStudio/Core/Def/Implementation/AnalyzerDependency/AnalyzerFileWatcherService.cs index 6e10df52981f1..9a23321c50303 100644 --- a/src/VisualStudio/Core/Def/Implementation/AnalyzerDependency/AnalyzerFileWatcherService.cs +++ b/src/VisualStudio/Core/Def/Implementation/AnalyzerDependency/AnalyzerFileWatcherService.cs @@ -70,7 +70,7 @@ private void RaiseAnalyzerChangedWarning(ProjectId projectId, string analyzerPat } } - private DateTime? GetLastUpdateTimeUtc(string fullPath) + private static DateTime? GetLastUpdateTimeUtc(string fullPath) { try { diff --git a/src/VisualStudio/Core/Def/Implementation/CallHierarchy/CallHierarchyDetail.cs b/src/VisualStudio/Core/Def/Implementation/CallHierarchy/CallHierarchyDetail.cs index 3d733d228c774..83b3c0a82d705 100644 --- a/src/VisualStudio/Core/Def/Implementation/CallHierarchy/CallHierarchyDetail.cs +++ b/src/VisualStudio/Core/Def/Implementation/CallHierarchy/CallHierarchyDetail.cs @@ -36,7 +36,7 @@ public CallHierarchyDetail(Location location, Workspace workspace) _text = ComputeText(location); } - private string ComputeText(Location location) + private static string ComputeText(Location location) { var lineSpan = location.GetLineSpan(); var start = location.SourceTree.GetText().Lines[lineSpan.StartLinePosition.Line].Start; diff --git a/src/VisualStudio/Core/Def/Implementation/CallHierarchy/CallHierarchyProvider.cs b/src/VisualStudio/Core/Def/Implementation/CallHierarchy/CallHierarchyProvider.cs index 8562869b2c532..9b0effeae02a7 100644 --- a/src/VisualStudio/Core/Def/Implementation/CallHierarchy/CallHierarchyProvider.cs +++ b/src/VisualStudio/Core/Def/Implementation/CallHierarchy/CallHierarchyProvider.cs @@ -66,7 +66,7 @@ SymbolKind.Event or return null; } - private ISymbol GetTargetSymbol(ISymbol symbol) + private static ISymbol GetTargetSymbol(ISymbol symbol) { if (symbol is IMethodSymbol methodSymbol) { diff --git a/src/VisualStudio/Core/Def/Implementation/CallHierarchy/Finders/AbstractCallFinder.cs b/src/VisualStudio/Core/Def/Implementation/CallHierarchy/Finders/AbstractCallFinder.cs index aa710bce4a3d5..c2a75143b2077 100644 --- a/src/VisualStudio/Core/Def/Implementation/CallHierarchy/Finders/AbstractCallFinder.cs +++ b/src/VisualStudio/Core/Def/Implementation/CallHierarchy/Finders/AbstractCallFinder.cs @@ -110,7 +110,7 @@ private async Task SearchAsync(Workspace workspace, CallHierarchySearchScope sco await SearchWorkerAsync(symbol, project, callback, documents, cancellationToken).ConfigureAwait(false); } - private IImmutableSet IncludeDocuments(CallHierarchySearchScope scope, Project project) + private static IImmutableSet IncludeDocuments(CallHierarchySearchScope scope, Project project) { if (scope is CallHierarchySearchScope.CurrentDocument or CallHierarchySearchScope.CurrentProject) { diff --git a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureDialogViewModel.ParameterViewModels.cs b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureDialogViewModel.ParameterViewModels.cs index 1e89465e6d630..07bef11bebee8 100644 --- a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureDialogViewModel.ParameterViewModels.cs +++ b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureDialogViewModel.ParameterViewModels.cs @@ -40,7 +40,7 @@ public ParameterViewModel(ChangeSignatureDialogViewModel changeSignatureDialogVi ChangeSignatureDialogViewModel = changeSignatureDialogViewModel; } - private string ValueOrNone(string value) + private static string ValueOrNone(string value) { return !string.IsNullOrEmpty(value) ? value diff --git a/src/VisualStudio/Core/Def/Implementation/CodeCleanup/AbstractCodeCleanUpFixer.cs b/src/VisualStudio/Core/Def/Implementation/CodeCleanup/AbstractCodeCleanUpFixer.cs index 38943b89d3ebc..347f758405c71 100644 --- a/src/VisualStudio/Core/Def/Implementation/CodeCleanup/AbstractCodeCleanUpFixer.cs +++ b/src/VisualStudio/Core/Def/Implementation/CodeCleanup/AbstractCodeCleanUpFixer.cs @@ -9,11 +9,13 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeCleanup; using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -42,15 +44,18 @@ internal abstract class AbstractCodeCleanUpFixer : ICodeCleanUpFixer private readonly IThreadingContext _threadingContext; private readonly VisualStudioWorkspaceImpl _workspace; private readonly IVsHierarchyItemManager _vsHierarchyItemManager; + private readonly IGlobalOptionService _globalOptions; protected AbstractCodeCleanUpFixer( IThreadingContext threadingContext, VisualStudioWorkspaceImpl workspace, - IVsHierarchyItemManager vsHierarchyItemManager) + IVsHierarchyItemManager vsHierarchyItemManager, + IGlobalOptionService globalOptions) { _threadingContext = threadingContext; _workspace = workspace; _vsHierarchyItemManager = vsHierarchyItemManager; + _globalOptions = globalOptions; } public Task FixAsync(ICodeCleanUpScope scope, ICodeCleanUpExecutionContext context) @@ -127,7 +132,9 @@ private async Task FixHierarchyContentAsync(IVsHierarchyCodeCleanupScope h return false; } - return await FixDocumentAsync(solution.GetRequiredDocument(documentId), context).ConfigureAwait(true); + var document = solution.GetRequiredDocument(documentId); + var options = _globalOptions.GetCodeActionOptions(document.Project.Language, isBlocking: false); + return await FixDocumentAsync(document, options, context).ConfigureAwait(true); } } @@ -157,14 +164,14 @@ async Task ApplyFixAsync(ProgressTracker progressTracker, Cancellation } } - private Task FixDocumentAsync(Document document, ICodeCleanUpExecutionContext context) + private Task FixDocumentAsync(Document document, CodeActionOptions options, ICodeCleanUpExecutionContext context) { return FixAsync(document.Project.Solution.Workspace, ApplyFixAsync, context); // Local function async Task ApplyFixAsync(ProgressTracker progressTracker, CancellationToken cancellationToken) { - var newDocument = await FixDocumentAsync(document, context.EnabledFixIds, progressTracker, cancellationToken).ConfigureAwait(true); + var newDocument = await FixDocumentAsync(document, context.EnabledFixIds, progressTracker, options, cancellationToken).ConfigureAwait(true); return newDocument.Project.Solution; } } @@ -194,7 +201,9 @@ async Task ApplyFixAsync(ProgressTracker progressTracker, Cancellation { var document = buffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges(); Contract.ThrowIfNull(document); - var newDoc = await FixDocumentAsync(document, context.EnabledFixIds, progressTracker, cancellationToken).ConfigureAwait(true); + + var options = _globalOptions.GetCodeActionOptions(document.Project.Language, isBlocking: false); + var newDoc = await FixDocumentAsync(document, context.EnabledFixIds, progressTracker, options, cancellationToken).ConfigureAwait(true); return newDoc.Project.Solution; } } @@ -280,6 +289,8 @@ private async Task FixProjectAsync( progressTracker.AddItems(project.DocumentIds.Count); } + var options = _globalOptions.GetCodeActionOptions(project.Language, isBlocking: false); + foreach (var documentId in project.DocumentIds) { cancellationToken.ThrowIfCancellationRequested(); @@ -291,7 +302,7 @@ private async Task FixProjectAsync( // to the current document. var documentProgressTracker = new ProgressTracker(); - var fixedDocument = await FixDocumentAsync(document, enabledFixIds, documentProgressTracker, cancellationToken).ConfigureAwait(false); + var fixedDocument = await FixDocumentAsync(document, enabledFixIds, documentProgressTracker, options, cancellationToken).ConfigureAwait(false); project = fixedDocument.Project; progressTracker.ItemCompleted(); } @@ -302,10 +313,11 @@ private async Task FixProjectAsync( private static bool CanCleanupProject(Project project) => project.LanguageServices.GetService() != null; - private async Task FixDocumentAsync( + private static async Task FixDocumentAsync( Document document, FixIdContainer enabledFixIds, ProgressTracker progressTracker, + CodeActionOptions options, CancellationToken cancellationToken) { if (document.IsGeneratedCode(cancellationToken)) @@ -340,7 +352,7 @@ private async Task FixDocumentAsync( new OrganizeUsingsSet(isRemoveUnusedUsingsEnabled, isSortUsingsEnabled)); return await codeCleanupService.CleanupAsync( - document, enabledDiagnostics, progressTracker, cancellationToken).ConfigureAwait(false); + document, enabledDiagnostics, progressTracker, options, cancellationToken).ConfigureAwait(false); } } } diff --git a/src/VisualStudio/Core/Def/Implementation/ColorSchemes/ColorSchemeApplier.RegistryItem.cs b/src/VisualStudio/Core/Def/Implementation/ColorSchemes/ColorSchemeApplier.RegistryItem.cs index 91c86a2175fab..4041e0a006451 100644 --- a/src/VisualStudio/Core/Def/Implementation/ColorSchemes/ColorSchemeApplier.RegistryItem.cs +++ b/src/VisualStudio/Core/Def/Implementation/ColorSchemes/ColorSchemeApplier.RegistryItem.cs @@ -9,7 +9,7 @@ internal partial class ColorSchemeApplier private class RegistryItem { public string SectionName { get; } - public string ValueName => "Data"; + public static string ValueName => "Data"; public byte[] ValueData { get; } public RegistryItem(string sectionName, byte[] valueData) diff --git a/src/VisualStudio/Core/Def/Implementation/ColorSchemes/ColorSchemeApplier.Settings.cs b/src/VisualStudio/Core/Def/Implementation/ColorSchemes/ColorSchemeApplier.Settings.cs index 00dc1fdff7f10..e5827c6895ee9 100644 --- a/src/VisualStudio/Core/Def/Implementation/ColorSchemes/ColorSchemeApplier.Settings.cs +++ b/src/VisualStudio/Core/Def/Implementation/ColorSchemes/ColorSchemeApplier.Settings.cs @@ -32,7 +32,7 @@ public ColorSchemeSettings(IServiceProvider serviceProvider, IGlobalOptionServic _globalOptions = globalOptions; } - public ImmutableDictionary GetColorSchemes() + public static ImmutableDictionary GetColorSchemes() { return new[] { @@ -41,13 +41,13 @@ public ImmutableDictionary GetColorSchemes() }.ToImmutableDictionary(name => name, name => GetColorScheme(name)); } - private ColorScheme GetColorScheme(SchemeName schemeName) + private static ColorScheme GetColorScheme(SchemeName schemeName) { using var colorSchemeStream = GetColorSchemeXmlStream(schemeName); return ColorSchemeReader.ReadColorScheme(colorSchemeStream); } - private Stream GetColorSchemeXmlStream(SchemeName schemeName) + private static Stream GetColorSchemeXmlStream(SchemeName schemeName) { var assembly = Assembly.GetExecutingAssembly(); return assembly.GetManifestResourceStream($"Microsoft.VisualStudio.LanguageServices.ColorSchemes.{schemeName}.xml"); @@ -60,7 +60,7 @@ public void ApplyColorScheme(SchemeName schemeName, ImmutableArray foreach (var item in registryItems) { using var itemKey = registryRoot.CreateSubKey(item.SectionName); - itemKey.SetValue(item.ValueName, item.ValueData); + itemKey.SetValue(RegistryItem.ValueName, item.ValueData); // Flush RegistryKeys out of paranoia itemKey.Flush(); } diff --git a/src/VisualStudio/Core/Def/Implementation/ColorSchemes/ColorSchemeApplier.cs b/src/VisualStudio/Core/Def/Implementation/ColorSchemes/ColorSchemeApplier.cs index 2f39276be942e..64cef9ab935de 100644 --- a/src/VisualStudio/Core/Def/Implementation/ColorSchemes/ColorSchemeApplier.cs +++ b/src/VisualStudio/Core/Def/Implementation/ColorSchemes/ColorSchemeApplier.cs @@ -52,7 +52,7 @@ public ColorSchemeApplier( _serviceProvider = serviceProvider; _settings = new ColorSchemeSettings(_serviceProvider, globalOptions); - _colorSchemes = _settings.GetColorSchemes(); + _colorSchemes = ColorSchemeSettings.GetColorSchemes(); _classificationVerifier = new ClassificationVerifier(threadingContext, serviceProvider, _colorSchemes); _colorSchemeRegistryItems = new AsyncLazy>>(GetColorSchemeRegistryItemsAsync, cacheResult: true); diff --git a/src/VisualStudio/Core/Def/Implementation/CommonControls/MemberSelectionViewModel.cs b/src/VisualStudio/Core/Def/Implementation/CommonControls/MemberSelectionViewModel.cs index f87317a6c46a7..7246929295ed1 100644 --- a/src/VisualStudio/Core/Def/Implementation/CommonControls/MemberSelectionViewModel.cs +++ b/src/VisualStudio/Core/Def/Implementation/CommonControls/MemberSelectionViewModel.cs @@ -142,7 +142,7 @@ public void UpdateMembersBasedOnDestinationKind(TypeKind destinationType) } } - private void SelectMembers(ImmutableArray members, bool isChecked = true) + private static void SelectMembers(ImmutableArray members, bool isChecked = true) { foreach (var member in members.Where(viewModel => viewModel.IsCheckable)) { diff --git a/src/VisualStudio/Core/Def/Implementation/ContainedLanguageRefactorNotifyService.cs b/src/VisualStudio/Core/Def/Implementation/ContainedLanguageRefactorNotifyService.cs index 3b14e75571ab2..95687f3f12803 100644 --- a/src/VisualStudio/Core/Def/Implementation/ContainedLanguageRefactorNotifyService.cs +++ b/src/VisualStudio/Core/Def/Implementation/ContainedLanguageRefactorNotifyService.cs @@ -68,7 +68,7 @@ public bool TryOnAfterGlobalSymbolRenamed(Workspace workspace, IEnumerable data, ArrayBuilder filteredData) + private static void AddFilteredInfos(ImmutableArray data, ArrayBuilder filteredData) { using var _ = PooledHashSet.GetInstance(out var seenDocumentIds); @@ -282,7 +282,7 @@ private async Task NotifyCpsProjectSystemAsync( await Task.WhenAll(tasks).ConfigureAwait(false); } - private async Task NotifyCpsProjectSystemAsync( + private static async Task NotifyCpsProjectSystemAsync( IProjectItemDesignerTypeUpdateService updateService, DesignerAttributeData data, CancellationToken cancellationToken) diff --git a/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioDiagnosticAnalyzerService.cs b/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioDiagnosticAnalyzerService.cs index 366b7915854b8..95564ab59604c 100644 --- a/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioDiagnosticAnalyzerService.cs +++ b/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioDiagnosticAnalyzerService.cs @@ -131,7 +131,7 @@ public IReadOnlyDictionary> GetAllDiag } } - private IReadOnlyDictionary> Transform( + private static IReadOnlyDictionary> Transform( ImmutableDictionary> map) { // unfortunately, we had to do this since ruleset editor and us are set to use this signature diff --git a/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioVenusSpanMappingService.cs b/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioVenusSpanMappingService.cs index f13ba13b28744..e2c32be4f666e 100644 --- a/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioVenusSpanMappingService.cs +++ b/src/VisualStudio/Core/Def/Implementation/Diagnostics/VisualStudioVenusSpanMappingService.cs @@ -120,7 +120,7 @@ private bool TryAdjustSpanIfNeededForVenus( return startChanged || endChanged; } - private LinePositionSpan GetLinePositionSpan(LinePosition position1, LinePosition position2) + private static LinePositionSpan GetLinePositionSpan(LinePosition position1, LinePosition position2) { if (position1 <= position2) { diff --git a/src/VisualStudio/Core/Def/Implementation/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs b/src/VisualStudio/Core/Def/Implementation/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs index 6acb93c07d7c4..a1c5081eb77cc 100644 --- a/src/VisualStudio/Core/Def/Implementation/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs +++ b/src/VisualStudio/Core/Def/Implementation/FindReferences/Contexts/AbstractTableDataSourceFindUsagesContext.cs @@ -374,7 +374,7 @@ public sealed override ValueTask OnDefinitionFoundAsync(DefinitionItem definitio additionalProperties); } - private async Task<(ExcerptResult, SourceText)> ExcerptAsync( + private static async Task<(ExcerptResult, SourceText)> ExcerptAsync( SourceText sourceText, DocumentSpan documentSpan, ClassificationOptions options, CancellationToken cancellationToken) { var excerptService = documentSpan.Document.Services.GetService(); @@ -463,7 +463,7 @@ private ValueTask UpdateTableProgressAsync(ImmutableArray<(int current, int maxi return ValueTaskFactory.CompletedTask; } - protected DefinitionItem CreateNoResultsDefinitionItem(string message) + protected static DefinitionItem CreateNoResultsDefinitionItem(string message) => DefinitionItem.CreateNonNavigableItem( GlyphTags.GetTags(Glyph.StatusInformation), ImmutableArray.Create(new TaggedText(TextTags.Text, message))); diff --git a/src/VisualStudio/Core/Def/Implementation/FindReferences/Entries/DocumentSpanEntry.cs b/src/VisualStudio/Core/Def/Implementation/FindReferences/Entries/DocumentSpanEntry.cs index 13aec63e24620..e663b42f30535 100644 --- a/src/VisualStudio/Core/Def/Implementation/FindReferences/Entries/DocumentSpanEntry.cs +++ b/src/VisualStudio/Core/Def/Implementation/FindReferences/Entries/DocumentSpanEntry.cs @@ -246,7 +246,7 @@ private DisposableToolTip CreateDisposableToolTip(Document document, TextSpan so return controlService.CreateDisposableToolTip(document, textBuffer, contentSpan, EnvironmentColors.ToolWindowBackgroundBrushKey); } - private void SetStaticClassifications(ITextBuffer textBuffer, ImmutableArray classifiedSpans) + private static void SetStaticClassifications(ITextBuffer textBuffer, ImmutableArray classifiedSpans) { var key = PredefinedPreviewTaggerKeys.StaticClassificationSpansKey; textBuffer.Properties.RemoveProperty(key); diff --git a/src/VisualStudio/Core/Def/Implementation/FindReferences/FindUsagesOptions.cs b/src/VisualStudio/Core/Def/Implementation/FindReferences/FindUsagesOptions.cs index dd7b8b5a02dab..0165c716b56ef 100644 --- a/src/VisualStudio/Core/Def/Implementation/FindReferences/FindUsagesOptions.cs +++ b/src/VisualStudio/Core/Def/Implementation/FindReferences/FindUsagesOptions.cs @@ -31,8 +31,8 @@ public FindUsagesOptions() /// and we want to restore the value back to its original state when the user does the /// next FindReferences call. /// - public static readonly Option DefinitionGroupingPriority = new( + public static readonly Option2 DefinitionGroupingPriority = new( nameof(FindUsagesOptions), nameof(DefinitionGroupingPriority), defaultValue: -1, - storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(DefinitionGroupingPriority))); + storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(DefinitionGroupingPriority))); } } diff --git a/src/VisualStudio/Core/Def/Implementation/FindReferences/StreamingFindUsagesPresenter.cs b/src/VisualStudio/Core/Def/Implementation/FindReferences/StreamingFindUsagesPresenter.cs index d1cc017c9e933..8af4006e56801 100644 --- a/src/VisualStudio/Core/Def/Implementation/FindReferences/StreamingFindUsagesPresenter.cs +++ b/src/VisualStudio/Core/Def/Implementation/FindReferences/StreamingFindUsagesPresenter.cs @@ -240,7 +240,7 @@ private AbstractTableDataSourceFindUsagesContext StartSearchWithoutReferences( private void StoreCurrentGroupingPriority(IFindAllReferencesWindow window) { - _globalOptions.SetGlobalOption(FindUsagesOptions.DefinitionGroupingPriority, window.GetDefinitionColumn().GroupingPriority); + _globalOptions.SetGlobalOption(new OptionKey(FindUsagesOptions.DefinitionGroupingPriority), window.GetDefinitionColumn().GroupingPriority); } private void SetDefinitionGroupingPriority(IFindAllReferencesWindow window, int priority) diff --git a/src/VisualStudio/Core/Def/Implementation/GenerateType/GenerateTypeDialogViewModel.cs b/src/VisualStudio/Core/Def/Implementation/GenerateType/GenerateTypeDialogViewModel.cs index 57ffabd0dcb8f..a2b5a1b9c0b25 100644 --- a/src/VisualStudio/Core/Def/Implementation/GenerateType/GenerateTypeDialogViewModel.cs +++ b/src/VisualStudio/Core/Def/Implementation/GenerateType/GenerateTypeDialogViewModel.cs @@ -692,7 +692,7 @@ internal void UpdateFileNameExtension() this.FileName = currentFileName; } - private string UpdateExtension(string currentFileName, string desiredFileExtension, string undesiredFileExtension) + private static string UpdateExtension(string currentFileName, string desiredFileExtension, string undesiredFileExtension) { if (currentFileName.EndsWith(desiredFileExtension, StringComparison.OrdinalIgnoreCase)) { diff --git a/src/VisualStudio/Core/Def/Implementation/InlineRename/InlineRenameUndoManager.cs b/src/VisualStudio/Core/Def/Implementation/InlineRename/InlineRenameUndoManager.cs index 031848433de6f..2e741acba5f96 100644 --- a/src/VisualStudio/Core/Def/Implementation/InlineRename/InlineRenameUndoManager.cs +++ b/src/VisualStudio/Core/Def/Implementation/InlineRename/InlineRenameUndoManager.cs @@ -218,7 +218,7 @@ private IOleUndoManager GetUndoManager(ITextBuffer subjectBuffer) return null; } - private IEnumerable GetUndoUnits(IOleUndoManager undoManager) + private static IEnumerable GetUndoUnits(IOleUndoManager undoManager) { IEnumOleUndoUnits undoUnitEnumerator; try diff --git a/src/VisualStudio/Core/Def/Implementation/KeybindingReset/KeybindingResetDetector.cs b/src/VisualStudio/Core/Def/Implementation/KeybindingReset/KeybindingResetDetector.cs index b041b015aab18..af3d8fc725dce 100644 --- a/src/VisualStudio/Core/Def/Implementation/KeybindingReset/KeybindingResetDetector.cs +++ b/src/VisualStudio/Core/Def/Implementation/KeybindingReset/KeybindingResetDetector.cs @@ -59,8 +59,8 @@ internal sealed class KeybindingResetDetector : ForegroundThreadAffinitizedObjec private static readonly Guid s_resharperCommandGroup = new("47F03277-5055-4922-899C-0F7F30D26BF1"); private static readonly ImmutableArray s_statusOptions = ImmutableArray.Create( - KeybindingResetOptions.ReSharperStatus, - KeybindingResetOptions.NeedsReset); + new OptionKey(KeybindingResetOptions.ReSharperStatus), + new OptionKey(KeybindingResetOptions.NeedsReset)); private readonly IGlobalOptionService _globalOptions; private readonly System.IServiceProvider _serviceProvider; @@ -353,7 +353,7 @@ private void RestoreVsKeybindings() KeybindingsResetLogger.Log("KeybindingsReset"); - _globalOptions.SetGlobalOption(KeybindingResetOptions.NeedsReset, false); + _globalOptions.SetGlobalOption(new OptionKey(KeybindingResetOptions.NeedsReset), false); } private void OpenExtensionsHyperlink() @@ -363,13 +363,13 @@ private void OpenExtensionsHyperlink() VisualStudioNavigateToLinkService.StartBrowser(KeybindingsFwLink); KeybindingsResetLogger.Log("ExtensionsLink"); - _globalOptions.SetGlobalOption(KeybindingResetOptions.NeedsReset, false); + _globalOptions.SetGlobalOption(new OptionKey(KeybindingResetOptions.NeedsReset), false); } private void NeverShowAgain() { - _globalOptions.SetGlobalOption(KeybindingResetOptions.NeverShowAgain, true); - _globalOptions.SetGlobalOption(KeybindingResetOptions.NeedsReset, false); + _globalOptions.SetGlobalOption(new OptionKey(KeybindingResetOptions.NeverShowAgain), true); + _globalOptions.SetGlobalOption(new OptionKey(KeybindingResetOptions.NeedsReset), false); KeybindingsResetLogger.Log("NeverShowAgain"); // The only external references to this object are as callbacks, which are removed by the Shutdown method. diff --git a/src/VisualStudio/Core/Def/Implementation/KeybindingReset/KeybindingResetOptions.cs b/src/VisualStudio/Core/Def/Implementation/KeybindingReset/KeybindingResetOptions.cs index 29d0239a7ff93..103b11f617c16 100644 --- a/src/VisualStudio/Core/Def/Implementation/KeybindingReset/KeybindingResetOptions.cs +++ b/src/VisualStudio/Core/Def/Implementation/KeybindingReset/KeybindingResetOptions.cs @@ -16,21 +16,21 @@ internal sealed class KeybindingResetOptions : IOptionProvider { private const string LocalRegistryPath = @"Roslyn\Internal\KeybindingsStatus\"; - public static readonly Option ReSharperStatus = new(nameof(KeybindingResetOptions), + public static readonly Option2 ReSharperStatus = new(nameof(KeybindingResetOptions), nameof(ReSharperStatus), defaultValue: KeybindingReset.ReSharperStatus.NotInstalledOrDisabled, - storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(ReSharperStatus))); + storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(ReSharperStatus))); - public static readonly Option NeedsReset = new(nameof(KeybindingResetOptions), + public static readonly Option2 NeedsReset = new(nameof(KeybindingResetOptions), nameof(NeedsReset), defaultValue: false, - storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(NeedsReset))); + storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(NeedsReset))); - public static readonly Option NeverShowAgain = new(nameof(KeybindingResetOptions), + public static readonly Option2 NeverShowAgain = new(nameof(KeybindingResetOptions), nameof(NeverShowAgain), defaultValue: false, - storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(NeverShowAgain))); + storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(NeverShowAgain))); - public static readonly Option EnabledFeatureFlag = new(nameof(KeybindingResetOptions), + public static readonly Option2 EnabledFeatureFlag = new(nameof(KeybindingResetOptions), nameof(EnabledFeatureFlag), defaultValue: false, - storageLocations: new FeatureFlagStorageLocation("Roslyn.KeybindingResetEnabled")); + storageLocation: new FeatureFlagStorageLocation("Roslyn.KeybindingResetEnabled")); ImmutableArray IOptionProvider.Options { get; } = ImmutableArray.Create( ReSharperStatus, diff --git a/src/VisualStudio/Core/Def/Implementation/LanguageService/AbstractCreateServicesOnTextViewConnection.cs b/src/VisualStudio/Core/Def/Implementation/LanguageService/AbstractCreateServicesOnTextViewConnection.cs index d04cbe4013da0..04708151a0275 100644 --- a/src/VisualStudio/Core/Def/Implementation/LanguageService/AbstractCreateServicesOnTextViewConnection.cs +++ b/src/VisualStudio/Core/Def/Implementation/LanguageService/AbstractCreateServicesOnTextViewConnection.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Snippets; using Microsoft.VisualStudio.Text; @@ -29,6 +30,7 @@ internal abstract class AbstractCreateServicesOnTextViewConnection : IWpfTextVie private bool _initialized = false; protected VisualStudioWorkspace Workspace { get; } + protected IGlobalOptionService GlobalOptions { get; } protected virtual Task InitializeServiceForOpenedDocumentAsync(Document document) => Task.CompletedTask; @@ -40,11 +42,14 @@ protected virtual void OnSolutionRemoved() public AbstractCreateServicesOnTextViewConnection( VisualStudioWorkspace workspace, + IGlobalOptionService globalOptions, IAsynchronousOperationListenerProvider listenerProvider, IThreadingContext threadingContext, string languageName) { Workspace = workspace; + GlobalOptions = globalOptions; + _listener = listenerProvider.GetListener(FeatureAttribute.Workspace); _threadingContext = threadingContext; _languageName = languageName; diff --git a/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractDescriptionBuilder.cs b/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractDescriptionBuilder.cs index 680a760959257..ef4be5f12e6e8 100644 --- a/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractDescriptionBuilder.cs +++ b/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractDescriptionBuilder.cs @@ -443,14 +443,14 @@ private void BuildXmlDocumentation(ISymbol symbol, Compilation compilation) } } - private bool ShowReturnsDocumentation(ISymbol symbol) + private static bool ShowReturnsDocumentation(ISymbol symbol) { return (symbol.Kind == SymbolKind.NamedType && ((INamedTypeSymbol)symbol).TypeKind == TypeKind.Delegate) || symbol.Kind == SymbolKind.Method || symbol.Kind == SymbolKind.Property; } - private bool ShowValueDocumentation(ISymbol symbol) + private static bool ShowValueDocumentation(ISymbol symbol) { // is often used in places where was originally intended. Allow either to be used in // documentation comments since they are not likely to be used together and it's not clear which one a diff --git a/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractListItemFactory.cs b/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractListItemFactory.cs index 5e2cb5773eda4..8bfa16b24464a 100644 --- a/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractListItemFactory.cs +++ b/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractListItemFactory.cs @@ -164,7 +164,7 @@ private static bool IncludeMemberSymbol(ISymbol symbol, IAssemblySymbol assembly return false; } - private ImmutableArray CreateListItemsFromSymbols( + private static ImmutableArray CreateListItemsFromSymbols( ImmutableArray symbols, Compilation compilation, ProjectId projectId, @@ -313,7 +313,7 @@ private ImmutableArray GetMemberListItems( return builder.ToImmutable(); } - private ImmutableArray GetMemberSymbols(INamedTypeSymbol namedTypeSymbol, Compilation compilation) + private static ImmutableArray GetMemberSymbols(INamedTypeSymbol namedTypeSymbol, Compilation compilation) { var members = namedTypeSymbol.GetMembers(); var symbolBuilder = ImmutableArray.CreateBuilder(members.Length); @@ -329,7 +329,7 @@ private ImmutableArray GetMemberSymbols(INamedTypeSymbol namedTypeSymbo return symbolBuilder.ToImmutable(); } - private ImmutableArray GetInheritedMemberSymbols(INamedTypeSymbol namedTypeSymbol, Compilation compilation) + private static ImmutableArray GetInheritedMemberSymbols(INamedTypeSymbol namedTypeSymbol, Compilation compilation) { var symbolBuilder = ImmutableArray.CreateBuilder(); @@ -373,7 +373,7 @@ private ImmutableArray GetInheritedMemberSymbols(INamedTypeSymbol named return symbolBuilder.ToImmutable(); } - private void AddOverriddenMembers(INamedTypeSymbol namedTypeSymbol, ref HashSet overriddenMembers) + private static void AddOverriddenMembers(INamedTypeSymbol namedTypeSymbol, ref HashSet overriddenMembers) { foreach (var member in namedTypeSymbol.GetMembers()) { @@ -539,7 +539,7 @@ public ImmutableHashSet> GetAssemblySet(Projec return set.ToImmutable(); } - private bool ContainsAccessibleTypeMember(INamespaceOrTypeSymbol namespaceOrTypeSymbol, IAssemblySymbol assemblySymbol) + private static bool ContainsAccessibleTypeMember(INamespaceOrTypeSymbol namespaceOrTypeSymbol, IAssemblySymbol assemblySymbol) { foreach (var typeMember in namespaceOrTypeSymbol.GetTypeMembers()) { @@ -552,7 +552,7 @@ private bool ContainsAccessibleTypeMember(INamespaceOrTypeSymbol namespaceOrType return false; } - private ImmutableArray GetAccessibleTypeMembers(INamespaceOrTypeSymbol namespaceOrTypeSymbol, IAssemblySymbol assemblySymbol) + private static ImmutableArray GetAccessibleTypeMembers(INamespaceOrTypeSymbol namespaceOrTypeSymbol, IAssemblySymbol assemblySymbol) { var typeMembers = namespaceOrTypeSymbol.GetTypeMembers(); var builder = ImmutableArray.CreateBuilder(typeMembers.Length); @@ -568,7 +568,7 @@ private ImmutableArray GetAccessibleTypeMembers(INamespaceOrTy return builder.ToImmutable(); } - private bool IncludeTypeMember(INamedTypeSymbol typeMember, IAssemblySymbol assemblySymbol) + private static bool IncludeTypeMember(INamedTypeSymbol typeMember, IAssemblySymbol assemblySymbol) { if (!IncludeSymbol(typeMember)) { @@ -670,7 +670,7 @@ public ImmutableArray GetReferenceListItems(ObjectListItem paren return builder.ToImmutableAndFree(); } - private ImmutableArray GetAccessibleTypes(INamespaceSymbol namespaceSymbol, Compilation compilation) + private static ImmutableArray GetAccessibleTypes(INamespaceSymbol namespaceSymbol, Compilation compilation) { var typeMembers = GetAccessibleTypeMembers(namespaceSymbol, compilation.Assembly); var builder = ImmutableArray.CreateBuilder(typeMembers.Length); diff --git a/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs b/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs index ef568a77b161d..e21c364bc9cff 100644 --- a/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs +++ b/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs @@ -512,7 +512,7 @@ protected override bool TryExec(Guid commandGroup, uint commandId) return false; } - private async Task FindReferencesAsync( + private static async Task FindReferencesAsync( IStreamingFindUsagesPresenter presenter, SymbolListItem symbolListItem, Project project) { try diff --git a/src/VisualStudio/Core/Def/Implementation/Log/LoggerOptions.cs b/src/VisualStudio/Core/Def/Implementation/Log/LoggerOptions.cs index 8eee7e1f931b7..8fb46abaf7f3d 100644 --- a/src/VisualStudio/Core/Def/Implementation/Log/LoggerOptions.cs +++ b/src/VisualStudio/Core/Def/Implementation/Log/LoggerOptions.cs @@ -29,13 +29,13 @@ public LoggerOptions() private const string LocalRegistryPath = @"Roslyn\Internal\Performance\Logger\"; - public static readonly Option EtwLoggerKey = new(nameof(LoggerOptions), nameof(EtwLoggerKey), defaultValue: true, - storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + "EtwLogger")); + public static readonly Option2 EtwLoggerKey = new(nameof(LoggerOptions), nameof(EtwLoggerKey), defaultValue: true, + storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "EtwLogger")); - public static readonly Option TraceLoggerKey = new(nameof(LoggerOptions), nameof(TraceLoggerKey), defaultValue: false, - storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + "TraceLogger")); + public static readonly Option2 TraceLoggerKey = new(nameof(LoggerOptions), nameof(TraceLoggerKey), defaultValue: false, + storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "TraceLogger")); - public static readonly Option OutputWindowLoggerKey = new(nameof(LoggerOptions), nameof(OutputWindowLoggerKey), defaultValue: false, - storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + "OutputWindowLogger")); + public static readonly Option2 OutputWindowLoggerKey = new(nameof(LoggerOptions), nameof(OutputWindowLoggerKey), defaultValue: false, + storageLocation: new LocalUserProfileStorageLocation(LocalRegistryPath + "OutputWindowLogger")); } } diff --git a/src/VisualStudio/Core/Def/Implementation/Log/VisualStudioErrorLogger.cs b/src/VisualStudio/Core/Def/Implementation/Log/VisualStudioErrorLogger.cs index 12d5567ca97eb..02fa5b5deaf86 100644 --- a/src/VisualStudio/Core/Def/Implementation/Log/VisualStudioErrorLogger.cs +++ b/src/VisualStudio/Core/Def/Implementation/Log/VisualStudioErrorLogger.cs @@ -34,7 +34,7 @@ public void LogException(object source, Exception exception) } } - private bool ShouldReportCrashDumps(object source) => HasRoslynPublicKey(source); + private static bool ShouldReportCrashDumps(object source) => HasRoslynPublicKey(source); private static string ToLogFormat(Exception exception) => exception.Message + Environment.NewLine + exception.StackTrace; diff --git a/src/VisualStudio/Core/Def/Implementation/MoveStaticMembers/StaticMemberSelectionViewModel.cs b/src/VisualStudio/Core/Def/Implementation/MoveStaticMembers/StaticMemberSelectionViewModel.cs index 69a10d6865c97..5c67933867864 100644 --- a/src/VisualStudio/Core/Def/Implementation/MoveStaticMembers/StaticMemberSelectionViewModel.cs +++ b/src/VisualStudio/Core/Def/Implementation/MoveStaticMembers/StaticMemberSelectionViewModel.cs @@ -72,7 +72,7 @@ public void SelectDependents() } } - private void SelectMembers(ImmutableArray> members, bool isChecked = true) + private static void SelectMembers(ImmutableArray> members, bool isChecked = true) { foreach (var member in members) { diff --git a/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersister.cs b/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersister.cs index 79d4f7658486b..2d46f1c5ecc3e 100644 --- a/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersister.cs +++ b/src/VisualStudio/Core/Def/Implementation/Options/LanguageSettingsPersister.cs @@ -30,7 +30,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options internal sealed class LanguageSettingsPersister : ForegroundThreadAffinitizedObject, IVsTextManagerEvents4, IOptionPersister { private readonly IVsTextManager4 _textManager; - private readonly IGlobalOptionService _optionService; + private readonly IGlobalOptionService _globalOptions; #pragma warning disable IDE0052 // Remove unread private members - https://github.com/dotnet/roslyn/issues/46167 private readonly ComEventSink _textManagerEvents2Sink; @@ -51,11 +51,11 @@ internal sealed class LanguageSettingsPersister : ForegroundThreadAffinitizedObj public LanguageSettingsPersister( IThreadingContext threadingContext, IVsTextManager4 textManager, - IGlobalOptionService optionService) + IGlobalOptionService globalOptions) : base(threadingContext, assertIsForeground: true) { _textManager = textManager; - _optionService = optionService; + _globalOptions = globalOptions; var languageMap = BidirectionalMap>.Empty; @@ -92,8 +92,8 @@ void InitializeSettingsForLanguage(string languageName, Guid languageGuid) FormattingOptions.TabSize, FormattingOptions.SmartIndent, FormattingOptions.IndentationSize, - CompletionOptions.Metadata.HideAdvancedMembers, - CompletionOptions.Metadata.TriggerOnTyping, + CompletionOptionsStorage.HideAdvancedMembers, + CompletionOptionsStorage.TriggerOnTyping, SignatureHelpViewOptions.ShowSignatureHelp, NavigationBarViewOptions.ShowNavigationBar }; @@ -129,7 +129,7 @@ private void RefreshLanguageSettings(LANGPREFERENCES3[] langPrefs, string langua var keyWithLanguage = new OptionKey(option, languageName); var newValue = GetValueForOption(option, langPrefs[0]); - _optionService.RefreshOption(keyWithLanguage, newValue); + _globalOptions.RefreshOption(keyWithLanguage, newValue); } } @@ -159,11 +159,11 @@ private static object GetValueForOption(IOption option, LANGPREFERENCES3 languag return FormattingOptions.IndentStyle.Smart; } } - else if (option == CompletionOptions.Metadata.HideAdvancedMembers) + else if (option == CompletionOptionsStorage.HideAdvancedMembers) { return languagePreference.fHideAdvancedAutoListMembers != 0; } - else if (option == CompletionOptions.Metadata.TriggerOnTyping) + else if (option == CompletionOptionsStorage.TriggerOnTyping) { return languagePreference.fAutoListMembers != 0; } @@ -210,11 +210,11 @@ private static void SetValueForOption(IOption option, ref LANGPREFERENCES3 langu break; } } - else if (option == CompletionOptions.Metadata.HideAdvancedMembers) + else if (option == CompletionOptionsStorage.HideAdvancedMembers) { languagePreference.fHideAdvancedAutoListMembers = Convert.ToUInt32((bool)value ? 1 : 0); } - else if (option == CompletionOptions.Metadata.TriggerOnTyping) + else if (option == CompletionOptionsStorage.TriggerOnTyping) { languagePreference.fAutoListMembers = Convert.ToUInt32((bool)value ? 1 : 0); } diff --git a/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersister.cs b/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersister.cs index ba6cef9bc667c..7d4eb04f6ff3c 100644 --- a/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersister.cs +++ b/src/VisualStudio/Core/Def/Implementation/Options/RoamingVisualStudioProfileOptionPersister.cs @@ -207,7 +207,7 @@ public bool TryFetch(OptionKey optionKey, out object? value) return true; } - private bool DeserializeCodeStyleOption(ref object? value, Type type) + private static bool DeserializeCodeStyleOption(ref object? value, Type type) { if (value is string serializedValue) { diff --git a/src/VisualStudio/Core/Def/Implementation/Preview/FileChange.cs b/src/VisualStudio/Core/Def/Implementation/Preview/FileChange.cs index 0bce58856d0a5..af5229b9d2f7c 100644 --- a/src/VisualStudio/Core/Def/Implementation/Preview/FileChange.cs +++ b/src/VisualStudio/Core/Def/Implementation/Preview/FileChange.cs @@ -128,7 +128,7 @@ private ChangeList GetEntireDocumentAsSpanChange(TextDocument document) return new ChangeList(new[] { entireSpanChild }); } - private string GetDisplayText(string excerpt) + private static string GetDisplayText(string excerpt) { if (excerpt.Contains("\r\n")) { diff --git a/src/VisualStudio/Core/Def/Implementation/Preview/TopLevelChange.cs b/src/VisualStudio/Core/Def/Implementation/Preview/TopLevelChange.cs index 4c10ce91661dc..86023c327dbfd 100644 --- a/src/VisualStudio/Core/Def/Implementation/Preview/TopLevelChange.cs +++ b/src/VisualStudio/Core/Def/Implementation/Preview/TopLevelChange.cs @@ -68,7 +68,7 @@ public Solution GetUpdatedSolution(bool applyingChanges) return solution; } - private Solution ApplyFileChanges(Solution solution, IEnumerable fileChanges, bool applyingChanges) + private static Solution ApplyFileChanges(Solution solution, IEnumerable fileChanges, bool applyingChanges) { foreach (var fileChange in fileChanges) { @@ -179,7 +179,7 @@ void ApplyFileChangesCore( } } - private Solution ApplyReferenceChanges(Solution solution, IEnumerable referenceChanges) + private static Solution ApplyReferenceChanges(Solution solution, IEnumerable referenceChanges) { foreach (var referenceChange in referenceChanges) { diff --git a/src/VisualStudio/Core/Def/Implementation/PreviewPane/PreviewPane.xaml.cs b/src/VisualStudio/Core/Def/Implementation/PreviewPane/PreviewPane.xaml.cs index 96fed7d4a4d71..26fa46c87dda4 100644 --- a/src/VisualStudio/Core/Def/Implementation/PreviewPane/PreviewPane.xaml.cs +++ b/src/VisualStudio/Core/Def/Implementation/PreviewPane/PreviewPane.xaml.cs @@ -72,7 +72,11 @@ public PreviewPane( // Now set the actual title text. TitleRun.Text = title; - InitializeHyperlinks(helpLink, helpLinkToolTipText); + if (helpLink != null) + { + Contract.ThrowIfNull(helpLinkToolTipText); + InitializeHyperlinks(helpLink, helpLinkToolTipText); + } if (!string.IsNullOrWhiteSpace(description)) { diff --git a/src/VisualStudio/Core/Def/Implementation/PreviewPane/PreviewPaneService.cs b/src/VisualStudio/Core/Def/Implementation/PreviewPane/PreviewPaneService.cs index ac49555687664..1b3772454ce1d 100644 --- a/src/VisualStudio/Core/Def/Implementation/PreviewPane/PreviewPaneService.cs +++ b/src/VisualStudio/Core/Def/Implementation/PreviewPane/PreviewPaneService.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; @@ -92,9 +93,6 @@ object IPreviewPaneService.GetPreviewPane(DiagnosticData data, IReadOnlyList GetCommands(IEnumerable nodes) } } - private bool IsOverridable(GraphNode node) + private static bool IsOverridable(GraphNode node) { var modifiers = GetModifiers(node); return (modifiers.IsVirtual || modifiers.IsAbstract || modifiers.IsOverride) && !modifiers.IsSealed; } - private DeclarationModifiers GetModifiers(GraphNode node) + private static DeclarationModifiers GetModifiers(GraphNode node) => (DeclarationModifiers)node[RoslynGraphProperties.SymbolModifiers]; - private bool CheckAccessibility(GraphNode node, Accessibility accessibility) + private static bool CheckAccessibility(GraphNode node, Accessibility accessibility) => node[RoslynGraphProperties.DeclaredAccessibility].Equals(accessibility); - private bool HasExplicitInterfaces(GraphNode node) + private static bool HasExplicitInterfaces(GraphNode node) => ((IList)node[RoslynGraphProperties.ExplicitInterfaceImplementations]).Count > 0; - private bool IsRoslynNode(GraphNode node) + private static bool IsRoslynNode(GraphNode node) { return node[RoslynGraphProperties.SymbolKind] != null && node[RoslynGraphProperties.TypeKind] != null; } - private bool IsAnySymbolKind(GraphNode node, params SymbolKind[] symbolKinds) + private static bool IsAnySymbolKind(GraphNode node, params SymbolKind[] symbolKinds) => symbolKinds.Any(k => k.Equals(node[RoslynGraphProperties.SymbolKind])); - private bool IsAnyTypeKind(GraphNode node, params TypeKind[] typeKinds) + private static bool IsAnyTypeKind(GraphNode node, params TypeKind[] typeKinds) => typeKinds.Any(k => node[RoslynGraphProperties.TypeKind].Equals(k)); private static readonly GraphCommandDefinition s_overridesCommandDefinition = diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioFrameworkAssemblyPathResolverFactory.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioFrameworkAssemblyPathResolverFactory.cs index 3b4aef3a4d80c..15cd5608d6441 100644 --- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioFrameworkAssemblyPathResolverFactory.cs +++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioFrameworkAssemblyPathResolverFactory.cs @@ -60,7 +60,7 @@ public Service(IThreadingContext threadingContext, VisualStudioWorkspace? worksp // full URI format (i.e. file://c:/...). This will allow us to get the // actual local in the normal path format. if (Uri.TryCreate(assembly.CodeBase, UriKind.RelativeOrAbsolute, out var uri) && - this.CanResolveType(assembly, fullyQualifiedTypeName)) + CanResolveType(assembly, fullyQualifiedTypeName)) { return uri.LocalPath; } @@ -69,7 +69,7 @@ public Service(IThreadingContext threadingContext, VisualStudioWorkspace? worksp return null; } - private bool CanResolveType(Assembly assembly, string? fullyQualifiedTypeName) + private static bool CanResolveType(Assembly assembly, string? fullyQualifiedTypeName) { if (fullyQualifiedTypeName == null) { diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReferenceManager.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReferenceManager.cs index a9ee5c9dfc260..07fc7f7e0a4f7 100644 --- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReferenceManager.cs +++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReferenceManager.cs @@ -216,7 +216,7 @@ private void GetStorageInfoFromTemporaryStorage(FileKey moduleFileKey, out ITemp pImage = directAccess.GetPointer(); } - private void StreamCopy(Stream source, Stream destination, int start, int length) + private static void StreamCopy(Stream source, Stream destination, int start, int length) { source.Position = start; @@ -312,7 +312,7 @@ private bool TryGetFileMappingFromMetadataImporter(FileKey fileKey, [NotNullWhen /// /// - private AssemblyMetadata CreateAssemblyMetadata( + private static AssemblyMetadata CreateAssemblyMetadata( FileKey fileKey, ModuleMetadata manifestModule, List? storages, Func?, ModuleMetadata> moduleMetadataFactory) { diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MiscellaneousFilesWorkspace.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MiscellaneousFilesWorkspace.cs index 5f8d87be7d51f..c4a3abf31ebce 100644 --- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MiscellaneousFilesWorkspace.cs +++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MiscellaneousFilesWorkspace.cs @@ -248,7 +248,7 @@ private bool TryUntrackClosingDocument(string moniker) return unregisteredRegistration; } - private bool IsClaimedByAnotherWorkspace(WorkspaceRegistration registration) + private static bool IsClaimedByAnotherWorkspace(WorkspaceRegistration registration) { // Currently, we are also responsible for pushing documents to the metadata as source workspace, // so we count that here as well diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.OpenFileTracker.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.OpenFileTracker.cs index 22bc495039551..134a02a33cac5 100644 --- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.OpenFileTracker.cs +++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.OpenFileTracker.cs @@ -7,6 +7,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; @@ -17,6 +18,7 @@ using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Threading; using Roslyn.Utilities; using IAsyncServiceProvider = Microsoft.VisualStudio.Shell.IAsyncServiceProvider; using Task = System.Threading.Tasks.Task; @@ -33,10 +35,17 @@ public sealed class OpenFileTracker : IRunningDocumentTableEventListener private readonly ForegroundThreadAffinitizedObject _foregroundAffinitization; private readonly VisualStudioWorkspaceImpl _workspace; + private readonly IThreadingContext _threadingContext; private readonly IAsynchronousOperationListener _asyncOperationListener; private readonly RunningDocumentTableEventTracker _runningDocumentTableEventTracker; + /// + /// Queue to process the workspace side of the document notifications we get. We process this in the BG to + /// avoid taking workspace locks on the UI thread. + /// + private readonly AsyncBatchingWorkQueue> _workspaceApplicationQueue; + #region Fields read/written to from multiple threads to track files that need to be checked /// @@ -63,11 +72,11 @@ public sealed class OpenFileTracker : IRunningDocumentTableEventListener private readonly ReferenceCountedDisposableCache _hierarchyEventSinkCache = new(); /// - /// The IVsHierarchies we have subscribed to to watch for any changes to this moniker. We track this per moniker, so - /// when a document is closed we know what we have to incrementally unsubscribe from rather than having to unsubscribe from everything. + /// The IVsHierarchies we have subscribed to watch for any changes to this moniker. We track this per + /// moniker, so when a document is closed we know what we have to incrementally unsubscribe from rather than + /// having to unsubscribe from everything. /// - private readonly MultiDictionary>> _watchedHierarchiesForDocumentMoniker - = new(); + private readonly MultiDictionary>> _watchedHierarchiesForDocumentMoniker = new(); #endregion @@ -83,13 +92,40 @@ private readonly MultiDictionary private const int CutoffForCheckingAllRunningDocumentTableDocuments = 10; - private OpenFileTracker(VisualStudioWorkspaceImpl workspace, IVsRunningDocumentTable runningDocumentTable, IComponentModel componentModel) + private OpenFileTracker( + VisualStudioWorkspaceImpl workspace, + IThreadingContext threadingContext, + IVsRunningDocumentTable runningDocumentTable, + IComponentModel componentModel) { _workspace = workspace; + _threadingContext = threadingContext; _foregroundAffinitization = new ForegroundThreadAffinitizedObject(workspace._threadingContext, assertIsForeground: true); _asyncOperationListener = componentModel.GetService().GetListener(FeatureAttribute.Workspace); _runningDocumentTableEventTracker = new RunningDocumentTableEventTracker(workspace._threadingContext, componentModel.GetService(), runningDocumentTable, this); + + _workspaceApplicationQueue = new AsyncBatchingWorkQueue>( + TimeSpan.FromMilliseconds(50), + ProcessWorkspaceApplicationQueueAsync, + _asyncOperationListener, + threadingContext.DisposalToken); + } + + private ValueTask ProcessWorkspaceApplicationQueueAsync(ImmutableArray> actions, CancellationToken cancellationToken) + { + // Take the workspace lock once, then apply all the changes we have while holding it. + return _workspace.ApplyChangeToWorkspaceMaybeAsync(useAsync: true, w => + { + foreach (var action in actions) + { + // Canceling here means we won't process the remaining workspace work. That's OK as we are only + // canceled during shutdown, and at that point we really don't want to be doing any unnecessary work + // anyways. + cancellationToken.ThrowIfCancellationRequested(); + action(w); + } + }, cancellationToken); } void IRunningDocumentTableEventListener.OnOpenDocument(string moniker, ITextBuffer textBuffer, IVsHierarchy? hierarchy, IVsWindowFrame? _) @@ -108,7 +144,10 @@ void IRunningDocumentTableEventListener.OnRenameDocument(string newMoniker, stri { } - public static async Task CreateAsync(VisualStudioWorkspaceImpl workspace, IAsyncServiceProvider asyncServiceProvider) + public static async Task CreateAsync( + VisualStudioWorkspaceImpl workspace, + IThreadingContext threadingContext, + IAsyncServiceProvider asyncServiceProvider) { var runningDocumentTable = (IVsRunningDocumentTable?)await asyncServiceProvider.GetServiceAsync(typeof(SVsRunningDocumentTable)).ConfigureAwait(true); Assumes.Present(runningDocumentTable); @@ -116,85 +155,114 @@ public static async Task CreateAsync(VisualStudioWorkspaceImpl var componentModel = (IComponentModel?)await asyncServiceProvider.GetServiceAsync(typeof(SComponentModel)).ConfigureAwait(true); Assumes.Present(componentModel); - return new OpenFileTracker(workspace, runningDocumentTable, componentModel); + return new OpenFileTracker(workspace, threadingContext, runningDocumentTable, componentModel); } private void TryOpeningDocumentsForMoniker(string moniker, ITextBuffer textBuffer, IVsHierarchy? hierarchy) { _foregroundAffinitization.AssertIsForeground(); - _workspace.ApplyChangeToWorkspace(w => - { - var documentIds = _workspace.CurrentSolution.GetDocumentIdsWithFilePath(moniker); - if (documentIds.IsDefaultOrEmpty) - { - return; - } + // First clear off any existing IVsHierarchies we are watching. Any ones that still matter we will + // resubscribe to. We could be fancy and diff, but the cost is probably negligible. Then watch and + // subscribe to this hierarchy and any related ones. + UnsubscribeFromWatchedHierarchies(moniker); + WatchAndSubscribeToHierarchies(moniker, hierarchy, out var contextHierarchy, out var contextHierarchyProjectName); - if (documentIds.All(w.IsDocumentOpen)) + _workspaceApplicationQueue.AddWork(w => { - return; - } + var documentIds = _workspace.CurrentSolution.GetDocumentIdsWithFilePath(moniker); + if (documentIds.IsDefaultOrEmpty) + { + return; + } - ProjectId activeContextProjectId; + if (documentIds.All(w.IsDocumentOpen)) + { + return; + } - if (documentIds.Length == 1) - { - activeContextProjectId = documentIds.Single().ProjectId; - } - else - { - activeContextProjectId = GetActiveContextProjectIdAndWatchHierarchies_NoLock(moniker, documentIds.Select(d => d.ProjectId), hierarchy); - } + var activeContextProjectId = documentIds.Length == 1 + ? documentIds.Single().ProjectId + : GetActiveContextProjectId_NoLock(contextHierarchy, contextHierarchyProjectName, documentIds.SelectAsArray(d => d.ProjectId)); - var textContainer = textBuffer.AsTextContainer(); + var textContainer = textBuffer.AsTextContainer(); - foreach (var documentId in documentIds) - { - if (!w.IsDocumentOpen(documentId) && !_workspace._documentsNotFromFiles.Contains(documentId)) + foreach (var documentId in documentIds) { - var isCurrentContext = documentId.ProjectId == activeContextProjectId; - if (w.CurrentSolution.ContainsDocument(documentId)) - { - w.OnDocumentOpened(documentId, textContainer, isCurrentContext); - } - else if (w.CurrentSolution.ContainsAdditionalDocument(documentId)) - { - w.OnAdditionalDocumentOpened(documentId, textContainer, isCurrentContext); - } - else + if (!w.IsDocumentOpen(documentId) && !_workspace._documentsNotFromFiles.Contains(documentId)) { - Debug.Assert(w.CurrentSolution.ContainsAnalyzerConfigDocument(documentId)); - w.OnAnalyzerConfigDocumentOpened(documentId, textContainer, isCurrentContext); + var isCurrentContext = documentId.ProjectId == activeContextProjectId; + if (w.CurrentSolution.ContainsDocument(documentId)) + { + w.OnDocumentOpened(documentId, textContainer, isCurrentContext); + } + else if (w.CurrentSolution.ContainsAdditionalDocument(documentId)) + { + w.OnAdditionalDocumentOpened(documentId, textContainer, isCurrentContext); + } + else + { + Debug.Assert(w.CurrentSolution.ContainsAnalyzerConfigDocument(documentId)); + w.OnAnalyzerConfigDocumentOpened(documentId, textContainer, isCurrentContext); + } } } - } - }); + }); } - private ProjectId GetActiveContextProjectIdAndWatchHierarchies_NoLock(string moniker, IEnumerable projectIds, IVsHierarchy? hierarchy) + /// + /// Gets the active project ID for the given hierarchy. Only callable while holding the workspace lock. + /// + private ProjectId GetActiveContextProjectId_NoLock( + IVsHierarchy? contextHierarchy, string? contextProjectName, ImmutableArray projectIds) { - _foregroundAffinitization.AssertIsForeground(); - - // First clear off any existing IVsHierarchies we are watching. Any ones that still matter we will resubscribe to. - // We could be fancy and diff, but the cost is probably negligible. - UnsubscribeFromWatchedHierarchies(moniker); - - if (hierarchy == null) + if (contextHierarchy == null) { // Any item in the RDT should have a hierarchy associated; in this case we don't so there's absolutely nothing // we can do at this point. return projectIds.First(); } - void WatchHierarchy(IVsHierarchy hierarchyToWatch) + // Take a snapshot of the immutable data structure here to avoid mutation underneath us + var projectToHierarchyMap = _workspace._projectToHierarchyMap; + + if (contextProjectName != null) { - _watchedHierarchiesForDocumentMoniker.Add(moniker, _hierarchyEventSinkCache.GetOrCreate(hierarchyToWatch, static (h, self) => new HierarchyEventSink(h, self), this)); + var project = _workspace.GetProjectWithHierarchyAndName_NoLock(contextHierarchy, contextProjectName); + + if (project != null && projectIds.Contains(project.Id)) + { + return project.Id; + } } - // Take a snapshot of the immutable data structure here to avoid mutation underneath us - var projectToHierarchyMap = _workspace._projectToHierarchyMap; - var solution = _workspace.CurrentSolution; + // At this point, we should hopefully have only one project that matches by hierarchy. If there's + // multiple, at this point we can't figure anything out better. + var matchingProjectId = projectIds.FirstOrDefault(id => projectToHierarchyMap.GetValueOrDefault(id, null) == contextHierarchy); + + if (matchingProjectId != null) + { + return matchingProjectId; + } + + // If we had some trouble finding the project, we'll just pick one arbitrarily + return projectIds.First(); + } + + private void WatchAndSubscribeToHierarchies(string moniker, IVsHierarchy? hierarchy, out IVsHierarchy? mappedHierarchy, out string? mappedHierarchyName) + { + // Keep this method in sync with GetActiveContextProjectId_NoLockAsync + + _foregroundAffinitization.AssertIsForeground(); + + if (hierarchy == null) + { + // Any item in the RDT should have a hierarchy associated; in this case we don't so there's absolutely nothing + // we can do at this point. + mappedHierarchy = null; + mappedHierarchyName = null; + return; + } // We now must chase to the actual hierarchy that we know about. First, we'll chase through multiple shared asset projects if // we need to do so. @@ -216,31 +284,16 @@ void WatchHierarchy(IVsHierarchy hierarchyToWatch) // We may have multiple projects with the same hierarchy, but we can use __VSHPROPID8.VSHPROPID_ActiveIntellisenseProjectContext to distinguish if (ErrorHandler.Succeeded(hierarchy.GetProperty(VSConstants.VSITEMID_ROOT, (int)__VSHPROPID8.VSHPROPID_ActiveIntellisenseProjectContext, out var contextProjectNameObject))) - { WatchHierarchy(hierarchy); - if (contextProjectNameObject is string contextProjectName) - { - var project = _workspace.GetProjectWithHierarchyAndName_NoLock(hierarchy, contextProjectName); - - if (project != null && projectIds.Contains(project.Id)) - { - return project.Id; - } - } - } - - // At this point, we should hopefully have only one project that maches by hierarchy. If there's multiple, at this point we can't figure anything - // out better. - var matchingProjectId = projectIds.FirstOrDefault(id => projectToHierarchyMap.GetValueOrDefault(id, null) == hierarchy); + mappedHierarchy = hierarchy; + mappedHierarchyName = contextProjectNameObject as string; + return; - if (matchingProjectId != null) + void WatchHierarchy(IVsHierarchy hierarchyToWatch) { - return matchingProjectId; + _watchedHierarchiesForDocumentMoniker.Add(moniker, _hierarchyEventSinkCache.GetOrCreate(hierarchyToWatch, static (h, self) => new HierarchyEventSink(h, self), this)); } - - // If we had some trouble finding the project, we'll just pick one arbitrarily - return projectIds.First(); } private void UnsubscribeFromWatchedHierarchies(string moniker) @@ -259,22 +312,30 @@ private void RefreshContextForMoniker(string moniker, IVsHierarchy hierarchy) { _foregroundAffinitization.AssertIsForeground(); - _workspace.ApplyChangeToWorkspace(w => - { - var documentIds = _workspace.CurrentSolution.GetDocumentIdsWithFilePath(moniker); - if (documentIds.IsDefaultOrEmpty || documentIds.Length == 1) - { - return; - } + // First clear off any existing IVsHierarchies we are watching. Any ones that still matter we will + // resubscribe to. We could be fancy and diff, but the cost is probably negligible. Then watch and + // subscribe to this hierarchy and any related ones. + UnsubscribeFromWatchedHierarchies(moniker); + WatchAndSubscribeToHierarchies(moniker, hierarchy, out var contextHierarchy, out var contextProjectName); - if (!documentIds.All(w.IsDocumentOpen)) + _workspaceApplicationQueue.AddWork(w => { - return; - } + var documentIds = _workspace.CurrentSolution.GetDocumentIdsWithFilePath(moniker); + if (documentIds.IsDefaultOrEmpty || documentIds.Length == 1) + { + return; + } - var activeProjectId = GetActiveContextProjectIdAndWatchHierarchies_NoLock(moniker, documentIds.Select(d => d.ProjectId), hierarchy); - w.OnDocumentContextUpdated(documentIds.First(d => d.ProjectId == activeProjectId)); - }); + if (!documentIds.All(w.IsDocumentOpen)) + { + return; + } + + var activeProjectId = GetActiveContextProjectId_NoLock( + contextHierarchy, contextProjectName, documentIds.SelectAsArray(d => d.ProjectId)); + + w.OnDocumentContextUpdated(documentIds.First(d => d.ProjectId == activeProjectId)); + }); } private void RefreshContextsForHierarchyPropertyChange(IVsHierarchy hierarchy) @@ -301,34 +362,34 @@ private void TryClosingDocumentsForMoniker(string moniker) UnsubscribeFromWatchedHierarchies(moniker); - _workspace.ApplyChangeToWorkspace(w => - { - var documentIds = w.CurrentSolution.GetDocumentIdsWithFilePath(moniker); - if (documentIds.IsDefaultOrEmpty) + _workspaceApplicationQueue.AddWork(w => { - return; - } + var documentIds = w.CurrentSolution.GetDocumentIdsWithFilePath(moniker); + if (documentIds.IsDefaultOrEmpty) + { + return; + } - foreach (var documentId in documentIds) - { - if (w.IsDocumentOpen(documentId) && !_workspace._documentsNotFromFiles.Contains(documentId)) + foreach (var documentId in documentIds) { - if (w.CurrentSolution.ContainsDocument(documentId)) - { - w.OnDocumentClosed(documentId, new FileTextLoader(moniker, defaultEncoding: null)); - } - else if (w.CurrentSolution.ContainsAdditionalDocument(documentId)) - { - w.OnAdditionalDocumentClosed(documentId, new FileTextLoader(moniker, defaultEncoding: null)); - } - else + if (w.IsDocumentOpen(documentId) && !_workspace._documentsNotFromFiles.Contains(documentId)) { - Debug.Assert(w.CurrentSolution.ContainsAnalyzerConfigDocument(documentId)); - w.OnAnalyzerConfigDocumentClosed(documentId, new FileTextLoader(moniker, defaultEncoding: null)); + if (w.CurrentSolution.ContainsDocument(documentId)) + { + w.OnDocumentClosed(documentId, new FileTextLoader(moniker, defaultEncoding: null)); + } + else if (w.CurrentSolution.ContainsAdditionalDocument(documentId)) + { + w.OnAdditionalDocumentClosed(documentId, new FileTextLoader(moniker, defaultEncoding: null)); + } + else + { + Debug.Assert(w.CurrentSolution.ContainsAnalyzerConfigDocument(documentId)); + w.OnAnalyzerConfigDocumentClosed(documentId, new FileTextLoader(moniker, defaultEncoding: null)); + } } } - } - }); + }); } /// diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs index 45587ada50892..776ea69ba6332 100644 --- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs +++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs @@ -214,7 +214,7 @@ public async Task InitializeUIAffinitizedServicesAsync(IAsyncServiceProvider asy var solutionClosingContext = UIContext.FromUIContextGuid(VSConstants.UICONTEXT.SolutionClosing_guid); solutionClosingContext.UIContextChanged += (_, e) => _solutionClosing = e.Activated; - var openFileTracker = await OpenFileTracker.CreateAsync(this, asyncServiceProvider).ConfigureAwait(true); + var openFileTracker = await OpenFileTracker.CreateAsync(this, _threadingContext, asyncServiceProvider).ConfigureAwait(true); var memoryListener = await VirtualMemoryNotificationListener.CreateAsync(this, _threadingContext, asyncServiceProvider, _globalOptions, _threadingContext.DisposalToken).ConfigureAwait(true); // Update our fields first, so any asynchronous work that needs to use these is able to see the service. @@ -546,7 +546,7 @@ internal bool TryAddReferenceToProject(ProjectId projectId, string assemblyName) return true; } - private string? GetAnalyzerPath(AnalyzerReference analyzerReference) + private static string? GetAnalyzerPath(AnalyzerReference analyzerReference) => analyzerReference.FullPath; protected override void ApplyCompilationOptionsChanged(ProjectId projectId, CompilationOptions options) @@ -628,7 +628,7 @@ protected override void ApplyAnalyzerReferenceRemoved(ProjectId projectId, Analy } } - private string? GetMetadataPath(MetadataReference metadataReference) + private static string? GetMetadataPath(MetadataReference metadataReference) { if (metadataReference is PortableExecutableReference fileMetadata) { @@ -882,7 +882,7 @@ private void AddDocumentCore(DocumentInfo info, SourceText initialText, TextDocu } } - private bool IsWebsite(EnvDTE.Project project) + private static bool IsWebsite(EnvDTE.Project project) => project.Kind == VsWebSite.PrjKind.prjKindVenusProject; private IEnumerable FilterFolderForProjectType(EnvDTE.Project project, IEnumerable folders) @@ -1284,7 +1284,7 @@ protected override void ApplyDocumentInfoChanged(DocumentId documentId, Document /// The currently supports only a subset of /// changes. /// - private void FailIfDocumentInfoChangesNotSupported(CodeAnalysis.Document document, DocumentInfo updatedInfo) + private static void FailIfDocumentInfoChangesNotSupported(CodeAnalysis.Document document, DocumentInfo updatedInfo) { if (document.SourceCodeKind != updatedInfo.SourceCodeKind) { @@ -1565,9 +1565,9 @@ public void ApplyChangeToWorkspace(Action action) /// /// Applies a single operation to the workspace. should be a call to one of the protected Workspace.On* methods. /// - public async ValueTask ApplyChangeToWorkspaceMaybeAsync(bool useAsync, Action action) + public async ValueTask ApplyChangeToWorkspaceMaybeAsync(bool useAsync, Action action, CancellationToken cancellationToken = default) { - using (useAsync ? await _gate.DisposableWaitAsync().ConfigureAwait(false) : _gate.DisposableWait()) + using (useAsync ? await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false) : _gate.DisposableWait(cancellationToken)) { action(this); } diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectTelemetry/VisualStudioProjectTelemetryService.cs b/src/VisualStudio/Core/Def/Implementation/ProjectTelemetry/VisualStudioProjectTelemetryService.cs index b5c3aeeebcfc5..a13a66baf570e 100644 --- a/src/VisualStudio/Core/Def/Implementation/ProjectTelemetry/VisualStudioProjectTelemetryService.cs +++ b/src/VisualStudio/Core/Def/Implementation/ProjectTelemetry/VisualStudioProjectTelemetryService.cs @@ -135,7 +135,7 @@ private async ValueTask NotifyTelemetryServiceAsync( await Task.WhenAll(tasks).ConfigureAwait(false); } - private void AddFilteredData(ImmutableArray infos, ArrayBuilder filteredInfos) + private static void AddFilteredData(ImmutableArray infos, ArrayBuilder filteredInfos) { using var _ = PooledHashSet.GetInstance(out var seenProjectIds); @@ -150,7 +150,7 @@ private void AddFilteredData(ImmutableArray infos, ArrayBu } } - private void NotifyTelemetryService(ProjectTelemetryData info) + private static void NotifyTelemetryService(ProjectTelemetryData info) { try { diff --git a/src/VisualStudio/Core/Def/Implementation/PullMemberUp/MainDialog/PullMemberUpDialog.xaml.cs b/src/VisualStudio/Core/Def/Implementation/PullMemberUp/MainDialog/PullMemberUpDialog.xaml.cs index 1b831a4625140..269abfb11e3df 100644 --- a/src/VisualStudio/Core/Def/Implementation/PullMemberUp/MainDialog/PullMemberUpDialog.xaml.cs +++ b/src/VisualStudio/Core/Def/Implementation/PullMemberUp/MainDialog/PullMemberUpDialog.xaml.cs @@ -61,7 +61,7 @@ private void OKButton_Click(object sender, RoutedEventArgs e) } } - private bool ShowWarningDialog(PullMembersUpOptions result) + private static bool ShowWarningDialog(PullMembersUpOptions result) { var warningViewModel = new PullMemberUpWarningViewModel(result); var warningDialog = new PullMemberUpWarningDialog(warningViewModel); diff --git a/src/VisualStudio/Core/Def/Implementation/PullMemberUp/WarningDialog/PullMemberUpWarningViewModel.cs b/src/VisualStudio/Core/Def/Implementation/PullMemberUp/WarningDialog/PullMemberUpWarningViewModel.cs index 36ff54d4d6e1e..0130be8dd1eaa 100644 --- a/src/VisualStudio/Core/Def/Implementation/PullMemberUp/WarningDialog/PullMemberUpWarningViewModel.cs +++ b/src/VisualStudio/Core/Def/Implementation/PullMemberUp/WarningDialog/PullMemberUpWarningViewModel.cs @@ -20,7 +20,7 @@ internal class PullMemberUpWarningViewModel : AbstractNotifyPropertyChanged public PullMemberUpWarningViewModel(PullMembersUpOptions options) => WarningMessageContainer = GenerateMessage(options); - private ImmutableArray GenerateMessage(PullMembersUpOptions options) + private static ImmutableArray GenerateMessage(PullMembersUpOptions options) { var warningMessagesBuilder = ImmutableArray.CreateBuilder(); diff --git a/src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetCommandHandler.cs b/src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetCommandHandler.cs index de2729e0c7fb7..7e34d02c3e245 100644 --- a/src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetCommandHandler.cs +++ b/src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetCommandHandler.cs @@ -292,32 +292,17 @@ protected bool TryHandleTypedSnippet(ITextView textView, ITextBuffer subjectBuff return false; } - var endPosition = endPositionInSubjectBuffer.Value.Position; - var startPosition = endPosition; - - // Find the snippet shortcut - while (startPosition > 0) - { - var c = currentText[startPosition - 1]; - if (!syntaxFactsService.IsIdentifierPartCharacter(c) && c != '#' && c != '~') - { - break; - } - - startPosition--; - } - - if (startPosition == endPosition) + if (!SnippetUtilities.TryGetWordOnLeft(endPositionInSubjectBuffer.Value.Position, currentText, syntaxFactsService, out var span)) { return false; } - if (!IsSnippetExpansionContext(document, startPosition, cancellationToken)) + if (!IsSnippetExpansionContext(document, span.Value.Start, cancellationToken)) { return false; } - return GetSnippetExpansionClient(textView, subjectBuffer).TryInsertExpansion(startPosition, endPosition, cancellationToken); + return GetSnippetExpansionClient(textView, subjectBuffer).TryInsertExpansion(span.Value.Start, span.Value.End, cancellationToken); } protected bool TryGetExpansionManager(out IVsExpansionManager expansionManager) diff --git a/src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetExpansionClient.cs b/src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetExpansionClient.cs index e26e572f8b790..427becb95f979 100644 --- a/src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetExpansionClient.cs +++ b/src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetExpansionClient.cs @@ -15,9 +15,8 @@ using System.Threading.Tasks; using System.Xml.Linq; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.Completion; -using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.SignatureHelp; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; @@ -130,9 +129,32 @@ public ImmutableArray GetArgumentProviders(Workspace workspace return _argumentProviders; } - public abstract int GetExpansionFunction(IXMLDOMNode xmlFunctionNode, string bstrFieldName, out IVsExpansionFunction? pFunc); + public int GetExpansionFunction(IXMLDOMNode xmlFunctionNode, string bstrFieldName, out IVsExpansionFunction? pFunc) + { + if (!SnippetFunctionService.TryGetSnippetFunctionInfo(xmlFunctionNode.text, out var snippetFunctionName, out var param)) + { + pFunc = null; + return VSConstants.E_INVALIDARG; + } + + switch (snippetFunctionName) + { + case "SimpleTypeName": + pFunc = new SnippetFunctionSimpleTypeName(this, SubjectBuffer, bstrFieldName, param, ThreadingContext); + return VSConstants.S_OK; + case "ClassName": + pFunc = new SnippetFunctionClassName(this, SubjectBuffer, bstrFieldName, ThreadingContext); + return VSConstants.S_OK; + case "GenerateSwitchCases": + pFunc = new SnippetFunctionGenerateSwitchCases(this, SubjectBuffer, bstrFieldName, param, ThreadingContext); + return VSConstants.S_OK; + default: + pFunc = null; + return VSConstants.E_INVALIDARG; + } + } protected abstract ITrackingSpan? InsertEmptyCommentAndGetEndPositionTrackingSpan(); - internal abstract Document AddImports(Document document, CodeGenerationPreferences preferences, int position, XElement snippetNode, bool allowInHiddenRegions, CancellationToken cancellationToken); + internal abstract Document AddImports(Document document, AddImportPlacementOptions options, int position, XElement snippetNode, CancellationToken cancellationToken); protected abstract string FallbackDefaultLiteral { get; } public int FormatSpan(IVsTextLines pBuffer, VsTextSpan[] tsInSurfaceBuffer) @@ -1054,14 +1076,13 @@ private void AddReferencesAndImports( return; } - var preferences = CodeGenerationPreferences.FromDocumentAsync(documentWithImports, cancellationToken).WaitAndGetResult(cancellationToken); - var allowInHiddenRegions = documentWithImports.CanAddImportsInHiddenRegions(); + var options = AddImportPlacementOptions.FromDocumentAsync(documentWithImports, cancellationToken).WaitAndGetResult(cancellationToken); - documentWithImports = AddImports(documentWithImports, preferences, position, snippetNode, allowInHiddenRegions, cancellationToken); + documentWithImports = AddImports(documentWithImports, options, position, snippetNode, cancellationToken); AddReferences(documentWithImports.Project, snippetNode); } - private void AddReferences(Project originalProject, XElement snippetNode) + private static void AddReferences(Project originalProject, XElement snippetNode) { var referencesNode = snippetNode.Element(XName.Get("References", snippetNode.Name.NamespaceName)); if (referencesNode == null) @@ -1133,28 +1154,6 @@ protected static bool TryAddImportsToContainedDocument(Document document, IEnume return true; } - protected static bool TryGetSnippetFunctionInfo( - IXMLDOMNode xmlFunctionNode, - [NotNullWhen(true)] out string? snippetFunctionName, - [NotNullWhen(true)] out string? param) - { - if (xmlFunctionNode.text.IndexOf('(') == -1 || - xmlFunctionNode.text.IndexOf(')') == -1 || - xmlFunctionNode.text.IndexOf(')') < xmlFunctionNode.text.IndexOf('(')) - { - snippetFunctionName = null; - param = null; - return false; - } - - snippetFunctionName = xmlFunctionNode.text.Substring(0, xmlFunctionNode.text.IndexOf('(')); - - var paramStart = xmlFunctionNode.text.IndexOf('(') + 1; - var paramLength = xmlFunctionNode.text.LastIndexOf(')') - xmlFunctionNode.text.IndexOf('(') - 1; - param = xmlFunctionNode.text.Substring(paramStart, paramLength); - return true; - } - internal bool TryGetSubjectBufferSpan(VsTextSpan surfaceBufferTextSpan, out SnapshotSpan subjectBufferSpan) { var snapshotSpan = TextView.TextSnapshot.GetSpan(surfaceBufferTextSpan); diff --git a/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/AbstractSnippetFunction.cs b/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/AbstractSnippetFunction.cs index 93da84f2e366a..2118db6f96f98 100644 --- a/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/AbstractSnippetFunction.cs +++ b/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/AbstractSnippetFunction.cs @@ -5,23 +5,28 @@ #nullable disable using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.TextManager.Interop; +using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets { internal abstract partial class AbstractSnippetFunction : IVsExpansionFunction { private readonly ITextBuffer _subjectBuffer; + private readonly IThreadingContext _threadingContext; protected AbstractSnippetExpansionClient snippetExpansionClient; - public AbstractSnippetFunction(AbstractSnippetExpansionClient snippetExpansionClient, ITextBuffer subjectBuffer) + public AbstractSnippetFunction(AbstractSnippetExpansionClient snippetExpansionClient, ITextBuffer subjectBuffer, IThreadingContext threadingContext) { this.snippetExpansionClient = snippetExpansionClient; _subjectBuffer = subjectBuffer; + _threadingContext = threadingContext; } protected bool TryGetDocument(out Document document) @@ -30,18 +35,30 @@ protected bool TryGetDocument(out Document document) return document != null; } - protected virtual int GetDefaultValue(CancellationToken cancellationToken, out string value, out int hasCurrentValue) + private int GetDefaultValue(CancellationToken cancellationToken, out string value, out int hasDefaultValue) { - value = string.Empty; - hasCurrentValue = 0; - return VSConstants.S_OK; + var (ExitCode, Value, HasDefaultValue) = _threadingContext.JoinableTaskFactory.Run(() => GetDefaultValueAsync(cancellationToken)); + value = Value; + hasDefaultValue = HasDefaultValue; + return ExitCode; } - protected virtual int GetCurrentValue(CancellationToken cancellationToken, out string value, out int hasCurrentValue) + protected virtual Task<(int ExitCode, string Value, int HasDefaultValue)> GetDefaultValueAsync(CancellationToken cancellationToken) { - value = string.Empty; - hasCurrentValue = 0; - return VSConstants.S_OK; + return Task.FromResult((ExitCode: VSConstants.S_OK, Value: string.Empty, HasDefaultValue: 0)); + } + + private int GetCurrentValue(CancellationToken cancellationToken, out string value, out int hasCurrentValue) + { + var (ExitCode, Value, HasCurrentValue) = _threadingContext.JoinableTaskFactory.Run(() => GetCurrentValueAsync(cancellationToken)); + value = Value; + hasCurrentValue = HasCurrentValue; + return ExitCode; + } + + protected virtual Task<(int ExitCode, string Value, int HasCurrentValue)> GetCurrentValueAsync(CancellationToken cancellationToken) + { + return Task.FromResult((ExitCode: VSConstants.S_OK, Value: string.Empty, HasDefaultValue: 0)); } protected virtual int FieldChanged(string field, out int requeryFunction) diff --git a/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/AbstractSnippetFunctionClassName.cs b/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/AbstractSnippetFunctionClassName.cs deleted file mode 100644 index fe163955c8c8a..0000000000000 --- a/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/AbstractSnippetFunctionClassName.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable disable - -using System.Threading; -using Microsoft.CodeAnalysis; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Editor; -using VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan; - -namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets -{ - internal abstract class AbstractSnippetFunctionClassName : AbstractSnippetFunction - { - protected readonly string FieldName; - - public AbstractSnippetFunctionClassName(AbstractSnippetExpansionClient snippetExpansionClient, ITextBuffer subjectBuffer, string fieldName) - : base(snippetExpansionClient, subjectBuffer) - { - this.FieldName = fieldName; - } - - protected abstract int GetContainingClassName(Document document, SnapshotSpan subjectBufferFieldSpan, CancellationToken cancellationToken, ref string value, ref int hasDefaultValue); - - protected override int GetDefaultValue(CancellationToken cancellationToken, out string value, out int hasDefaultValue) - { - hasDefaultValue = 0; - value = string.Empty; - if (!TryGetDocument(out var document)) - { - return VSConstants.E_FAIL; - } - - var surfaceBufferFieldSpan = new VsTextSpan[1]; - if (snippetExpansionClient.ExpansionSession.GetFieldSpan(FieldName, surfaceBufferFieldSpan) != VSConstants.S_OK) - { - return VSConstants.E_FAIL; - } - - if (!snippetExpansionClient.TryGetSubjectBufferSpan(surfaceBufferFieldSpan[0], out var subjectBufferFieldSpan)) - { - return VSConstants.E_FAIL; - } - - return GetContainingClassName(document, subjectBufferFieldSpan, cancellationToken, ref value, ref hasDefaultValue); - } - } -} diff --git a/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/AbstractSnippetFunctionGenerateSwitchCases.cs b/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/AbstractSnippetFunctionGenerateSwitchCases.cs deleted file mode 100644 index 8565d6bd73059..0000000000000 --- a/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/AbstractSnippetFunctionGenerateSwitchCases.cs +++ /dev/null @@ -1,104 +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.Text; -using System.Threading; -using Microsoft.CodeAnalysis; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Editor; -using Roslyn.Utilities; -using VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan; - -namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets.SnippetFunctions -{ - internal abstract class AbstractSnippetFunctionGenerateSwitchCases : AbstractSnippetFunction - { - protected readonly string CaseGenerationLocationField; - protected readonly string SwitchExpressionField; - - protected abstract string CaseFormat { get; } - protected abstract string DefaultCase { get; } - - public AbstractSnippetFunctionGenerateSwitchCases(AbstractSnippetExpansionClient snippetExpansionClient, ITextBuffer subjectBuffer, string caseGenerationLocationField, string switchExpressionField) - : base(snippetExpansionClient, subjectBuffer) - { - this.CaseGenerationLocationField = caseGenerationLocationField; - this.SwitchExpressionField = (switchExpressionField.Length >= 2 && switchExpressionField[0] == '$' && switchExpressionField[switchExpressionField.Length - 1] == '$') - ? switchExpressionField.Substring(1, switchExpressionField.Length - 2) : switchExpressionField; - } - - protected abstract bool TryGetEnumTypeSymbol(CancellationToken cancellationToken, out ITypeSymbol typeSymbol); - protected abstract bool TryGetSimplifiedTypeNameInCaseContext(Document document, string fullyQualifiedTypeName, string firstEnumMemberName, int startPosition, int endPosition, CancellationToken cancellationToken, out string simplifiedTypeName); - - protected override int FieldChanged(string field, out int requeryFunction) - { - requeryFunction = (SwitchExpressionField == field) ? 1 : 0; - return VSConstants.S_OK; - } - - protected override int GetCurrentValue(CancellationToken cancellationToken, out string value, out int hasCurrentValue) - { - // If the switch expression is invalid, still show the default case - value = DefaultCase; - hasCurrentValue = 1; - if (!TryGetEnumTypeSymbol(cancellationToken, out var typeSymbol) || typeSymbol.TypeKind != TypeKind.Enum) - { - return VSConstants.S_OK; - } - - var enumFields = typeSymbol.GetMembers().Where(m => m.Kind == SymbolKind.Field && m.IsStatic); - - // Find and use the most simplified legal version of the enum type name in this context - var simplifiedTypeName = string.Empty; - if (!enumFields.Any() || - !TryGetSimplifiedTypeName( - typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), - enumFields.First().Name, - cancellationToken, - out simplifiedTypeName)) - { - return VSConstants.S_OK; - } - - var casesBuilder = new StringBuilder(); - foreach (var member in enumFields) - { - casesBuilder.AppendFormat(CaseFormat, simplifiedTypeName, member.Name); - } - - casesBuilder.Append(DefaultCase); - value = casesBuilder.ToString(); - - return VSConstants.S_OK; - } - - private bool TryGetSimplifiedTypeName(string fullyQualifiedTypeName, string firstEnumMemberName, CancellationToken cancellationToken, out string simplifiedTypeName) - { - simplifiedTypeName = string.Empty; - if (!TryGetDocument(out var document)) - { - return false; - } - - // Add the first switch case using the fully qualified type name, then simplify it in - // that context - var surfaceBufferFieldSpan = new VsTextSpan[1]; - if (snippetExpansionClient.ExpansionSession.GetFieldSpan(CaseGenerationLocationField, surfaceBufferFieldSpan) != VSConstants.S_OK) - { - return false; - } - - if (!snippetExpansionClient.TryGetSubjectBufferSpan(surfaceBufferFieldSpan[0], out var subjectBufferFieldSpan)) - { - return false; - } - - return TryGetSimplifiedTypeNameInCaseContext(document, fullyQualifiedTypeName, firstEnumMemberName, subjectBufferFieldSpan.Start.Position, subjectBufferFieldSpan.End.Position, cancellationToken, out simplifiedTypeName); - } - } -} diff --git a/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/AbstractSnippetFunctionSimpleTypeName.cs b/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/AbstractSnippetFunctionSimpleTypeName.cs deleted file mode 100644 index e50ac74f44c03..0000000000000 --- a/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/AbstractSnippetFunctionSimpleTypeName.cs +++ /dev/null @@ -1,83 +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.Text; -using Microsoft.VisualStudio; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Editor; -using Roslyn.Utilities; -using TextSpan = Microsoft.CodeAnalysis.Text.TextSpan; -using VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan; - -namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets.SnippetFunctions -{ - internal abstract class AbstractSnippetFunctionSimpleTypeName : AbstractSnippetFunction - { - private readonly string _fieldName; - private readonly string _fullyQualifiedName; - - public AbstractSnippetFunctionSimpleTypeName(AbstractSnippetExpansionClient snippetExpansionClient, ITextBuffer subjectBuffer, string fieldName, string fullyQualifiedName) - : base(snippetExpansionClient, subjectBuffer) - { - _fieldName = fieldName; - _fullyQualifiedName = fullyQualifiedName; - } - - protected abstract bool TryGetSimplifiedTypeName(Document documentWithFullyQualifiedTypeName, TextSpan updatedTextSpan, CancellationToken cancellationToken, out string simplifiedTypeName); - - protected override int GetDefaultValue(CancellationToken cancellationToken, out string value, out int hasDefaultValue) - { - value = _fullyQualifiedName; - hasDefaultValue = 1; - if (!TryGetDocument(out var document)) - { - return VSConstants.E_FAIL; - } - - if (!TryGetDocumentWithFullyQualifiedTypeName(document, out var updatedTextSpan, out var documentWithFullyQualifiedTypeName)) - { - return VSConstants.E_FAIL; - } - - if (!TryGetSimplifiedTypeName(documentWithFullyQualifiedTypeName, updatedTextSpan, cancellationToken, out var simplifiedName)) - { - return VSConstants.E_FAIL; - } - - value = simplifiedName; - hasDefaultValue = 1; - return VSConstants.S_OK; - } - - private bool TryGetDocumentWithFullyQualifiedTypeName(Document document, out TextSpan updatedTextSpan, out Document documentWithFullyQualifiedTypeName) - { - documentWithFullyQualifiedTypeName = null; - updatedTextSpan = default; - - var surfaceBufferFieldSpan = new VsTextSpan[1]; - if (snippetExpansionClient.ExpansionSession.GetFieldSpan(_fieldName, surfaceBufferFieldSpan) != VSConstants.S_OK) - { - return false; - } - - if (!snippetExpansionClient.TryGetSubjectBufferSpan(surfaceBufferFieldSpan[0], out var subjectBufferFieldSpan)) - { - return false; - } - - var originalTextSpan = new TextSpan(subjectBufferFieldSpan.Start, subjectBufferFieldSpan.Length); - updatedTextSpan = new TextSpan(subjectBufferFieldSpan.Start, _fullyQualifiedName.Length); - - var textChange = new TextChange(originalTextSpan, _fullyQualifiedName); - var newText = document.GetTextSynchronously(CancellationToken.None).WithChanges(textChange); - - documentWithFullyQualifiedTypeName = document.WithText(newText); - return true; - } - } -} diff --git a/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/SnippetFunctionClassName.cs b/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/SnippetFunctionClassName.cs new file mode 100644 index 0000000000000..d0c4c1630cf65 --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/SnippetFunctionClassName.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. + +#nullable disable + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.VisualStudio.Text; +using VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets +{ + internal class SnippetFunctionClassName : AbstractSnippetFunction + { + protected readonly string FieldName; + + public SnippetFunctionClassName(AbstractSnippetExpansionClient snippetExpansionClient, ITextBuffer subjectBuffer, string fieldName, IThreadingContext threadingContext) + : base(snippetExpansionClient, subjectBuffer, threadingContext) + { + this.FieldName = fieldName; + } + + protected override async Task<(int ExitCode, string Value, int HasDefaultValue)> GetDefaultValueAsync(CancellationToken cancellationToken) + { + var hasDefaultValue = 0; + var value = string.Empty; + if (!TryGetDocument(out var document)) + { + return (VSConstants.E_FAIL, value, hasDefaultValue); + } + + var surfaceBufferFieldSpan = new VsTextSpan[1]; + if (snippetExpansionClient.ExpansionSession.GetFieldSpan(FieldName, surfaceBufferFieldSpan) != VSConstants.S_OK) + { + return (VSConstants.E_FAIL, value, hasDefaultValue); + } + + if (!snippetExpansionClient.TryGetSubjectBufferSpan(surfaceBufferFieldSpan[0], out var subjectBufferFieldSpan)) + { + return (VSConstants.E_FAIL, value, hasDefaultValue); + } + + var snippetFunctionService = document.Project.GetRequiredLanguageService(); + value = await snippetFunctionService.GetContainingClassNameAsync(document, subjectBufferFieldSpan.Start.Position, cancellationToken).ConfigureAwait(false); + + if (!string.IsNullOrWhiteSpace(value)) + { + hasDefaultValue = 1; + } + + return (VSConstants.S_OK, value, hasDefaultValue); + } + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs b/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs new file mode 100644 index 0000000000000..e5ae82936d202 --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/SnippetFunctionGenerateSwitchCases.cs @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.Text; +using VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets +{ + internal class SnippetFunctionGenerateSwitchCases : AbstractSnippetFunction + { + protected readonly string CaseGenerationLocationField; + protected readonly string SwitchExpressionField; + + public SnippetFunctionGenerateSwitchCases( + AbstractSnippetExpansionClient snippetExpansionClient, + ITextBuffer subjectBuffer, + string caseGenerationLocationField, + string switchExpressionField, + IThreadingContext threadingContext) + : base(snippetExpansionClient, subjectBuffer, threadingContext) + { + this.CaseGenerationLocationField = caseGenerationLocationField; + this.SwitchExpressionField = (switchExpressionField.Length >= 2 && switchExpressionField[0] == '$' && switchExpressionField[switchExpressionField.Length - 1] == '$') + ? switchExpressionField.Substring(1, switchExpressionField.Length - 2) : switchExpressionField; + } + + protected override int FieldChanged(string field, out int requeryFunction) + { + requeryFunction = (SwitchExpressionField == field) ? 1 : 0; + return VSConstants.S_OK; + } + + protected override async Task<(int ExitCode, string Value, int HasCurrentValue)> GetCurrentValueAsync(CancellationToken cancellationToken) + { + if (!TryGetDocument(out var document)) + { + return (VSConstants.S_OK, string.Empty, HasCurrentValue: 0); + } + + // If the switch expression is invalid, still show the default case + var hasCurrentValue = 1; + + var snippetFunctionService = document.Project.GetRequiredLanguageService(); + if (!TryGetSpan(SwitchExpressionField, out var switchExpressionSpan) || + !TryGetSpan(CaseGenerationLocationField, out var caseGenerationSpan)) + { + return (VSConstants.S_OK, snippetFunctionService.SwitchDefaultCaseForm, hasCurrentValue); + } + + var value = await snippetFunctionService.GetSwitchExpansionAsync(document, caseGenerationSpan.Value, switchExpressionSpan.Value, cancellationToken).ConfigureAwait(false); + if (value == null) + { + return (VSConstants.S_OK, snippetFunctionService.SwitchDefaultCaseForm, hasCurrentValue); + } + + return (VSConstants.S_OK, value, hasCurrentValue); + } + + private bool TryGetSpan(string fieldName, [NotNullWhen(true)] out TextSpan? switchExpressionSpan) + { + switchExpressionSpan = null; + var surfaceBufferFieldSpan = new VsTextSpan[1]; + if (snippetExpansionClient.ExpansionSession?.GetFieldSpan(fieldName, surfaceBufferFieldSpan) != VSConstants.S_OK) + { + return false; + } + + if (!snippetExpansionClient.TryGetSubjectBufferSpan(surfaceBufferFieldSpan[0], out var subjectBufferFieldSpan)) + { + return false; + } + + switchExpressionSpan = subjectBufferFieldSpan.Span.ToTextSpan(); + return true; + } + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs b/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs new file mode 100644 index 0000000000000..a4771e60f23c3 --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/Snippets/SnippetFunctions/SnippetFunctionSimpleTypeName.cs @@ -0,0 +1,80 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.VisualStudio.Text; +using TextSpan = Microsoft.CodeAnalysis.Text.TextSpan; +using VsTextSpan = Microsoft.VisualStudio.TextManager.Interop.TextSpan; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.Snippets +{ + internal class SnippetFunctionSimpleTypeName : AbstractSnippetFunction + { + private readonly string _fieldName; + private readonly string _fullyQualifiedName; + + public SnippetFunctionSimpleTypeName( + AbstractSnippetExpansionClient snippetExpansionClient, + ITextBuffer subjectBuffer, + string fieldName, + string fullyQualifiedName, + IThreadingContext threadingContext) + : base(snippetExpansionClient, subjectBuffer, threadingContext) + { + _fieldName = fieldName; + _fullyQualifiedName = fullyQualifiedName; + } + + protected override async Task<(int ExitCode, string Value, int HasDefaultValue)> GetDefaultValueAsync(CancellationToken cancellationToken) + { + var value = _fullyQualifiedName; + var hasDefaultValue = 1; + if (!TryGetDocument(out var document)) + { + return (VSConstants.E_FAIL, value, hasDefaultValue); + } + + if (!TryGetFieldSpan(out var fieldSpan)) + { + return (VSConstants.E_FAIL, value, hasDefaultValue); + } + + var simplifiedTypeName = await SnippetFunctionService.GetSimplifiedTypeNameAsync(document, fieldSpan.Value, _fullyQualifiedName, cancellationToken).ConfigureAwait(false); + if (string.IsNullOrEmpty(simplifiedTypeName)) + { + return (VSConstants.E_FAIL, value, hasDefaultValue); + } + + return (VSConstants.S_OK, simplifiedTypeName!, hasDefaultValue); + } + + private bool TryGetFieldSpan([NotNullWhen(true)] out TextSpan? fieldSpan) + { + fieldSpan = null; + var surfaceBufferFieldSpan = new VsTextSpan[1]; + if (snippetExpansionClient.ExpansionSession == null) + { + return false; + } + + if (snippetExpansionClient.ExpansionSession.GetFieldSpan(_fieldName, surfaceBufferFieldSpan) != VSConstants.S_OK) + { + return false; + } + + if (!snippetExpansionClient.TryGetSubjectBufferSpan(surfaceBufferFieldSpan[0], out var subjectBufferFieldSpan)) + { + return false; + } + + fieldSpan = new TextSpan(subjectBufferFieldSpan.Start, subjectBufferFieldSpan.Length); + return true; + } + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/TableDataSource/Suppression/VisualStudioDiagnosticListSuppressionStateService.cs b/src/VisualStudio/Core/Def/Implementation/TableDataSource/Suppression/VisualStudioDiagnosticListSuppressionStateService.cs index 0249f0e2519f5..e34b66bd51341 100644 --- a/src/VisualStudio/Core/Def/Implementation/TableDataSource/Suppression/VisualStudioDiagnosticListSuppressionStateService.cs +++ b/src/VisualStudio/Core/Def/Implementation/TableDataSource/Suppression/VisualStudioDiagnosticListSuppressionStateService.cs @@ -305,7 +305,6 @@ public async Task> GetSelectedItemsAsync(bool isA id: errorCode, category: category, message: message, - enuMessageForBingSearch: message, severity: DiagnosticSeverity.Warning, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true, diff --git a/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseDiagnosticListTable.LiveTableDataSource.cs b/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseDiagnosticListTable.LiveTableDataSource.cs index 64c938f530f67..27dc28d16fafd 100644 --- a/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseDiagnosticListTable.LiveTableDataSource.cs +++ b/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseDiagnosticListTable.LiveTableDataSource.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Common; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Shared; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Internal.Log; @@ -168,8 +169,9 @@ private object CreateAggregationKey(DiagnosticsUpdatedArgs data) private void PopulateInitialData(Workspace workspace, IDiagnosticService diagnosticService) { + var diagnosticMode = _globalOptions.GetDiagnosticMode(InternalDiagnosticsOptions.NormalDiagnosticMode); var diagnostics = diagnosticService.GetPushDiagnosticBuckets( - workspace, projectId: null, documentId: null, InternalDiagnosticsOptions.NormalDiagnosticMode, cancellationToken: CancellationToken.None); + workspace, projectId: null, documentId: null, diagnosticMode, cancellationToken: CancellationToken.None); foreach (var bucket in diagnostics) { @@ -212,7 +214,7 @@ private void OnDiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs e) public override AbstractTableEntriesSource CreateTableEntriesSource(object data) { var item = (UpdatedEventArgs)data; - return new TableEntriesSource(this, item.Workspace, item.ProjectId, item.DocumentId, item.Id); + return new TableEntriesSource(this, item.Workspace, _globalOptions, item.ProjectId, item.DocumentId, item.Id); } private void ConnectToDiagnosticService(Workspace workspace, IDiagnosticService diagnosticService) @@ -274,15 +276,17 @@ private class TableEntriesSource : DiagnosticTableEntriesSource { private readonly LiveTableDataSource _source; private readonly Workspace _workspace; + private readonly IGlobalOptionService _globalOptions; private readonly ProjectId? _projectId; private readonly DocumentId? _documentId; private readonly object _id; private readonly string _buildTool; - public TableEntriesSource(LiveTableDataSource source, Workspace workspace, ProjectId? projectId, DocumentId? documentId, object id) + public TableEntriesSource(LiveTableDataSource source, Workspace workspace, IGlobalOptionService globalOptions, ProjectId? projectId, DocumentId? documentId, object id) { _source = source; _workspace = workspace; + _globalOptions = globalOptions; _projectId = projectId; _documentId = documentId; _id = id; @@ -296,8 +300,9 @@ public TableEntriesSource(LiveTableDataSource source, Workspace workspace, Proje public override ImmutableArray GetItems() { + var diagnosticMode = _globalOptions.GetDiagnosticMode(InternalDiagnosticsOptions.NormalDiagnosticMode); var provider = _source._diagnosticService; - var items = provider.GetPushDiagnosticsAsync(_workspace, _projectId, _documentId, _id, includeSuppressedDiagnostics: true, InternalDiagnosticsOptions.NormalDiagnosticMode, cancellationToken: CancellationToken.None) + var items = provider.GetPushDiagnosticsAsync(_workspace, _projectId, _documentId, _id, includeSuppressedDiagnostics: true, diagnosticMode, cancellationToken: CancellationToken.None) .AsTask() .WaitAndGetResult_CanCallOnBackground(CancellationToken.None) .Where(ShouldInclude) @@ -349,13 +354,13 @@ public override bool TryGetValue(int index, string columnName, [NotNullWhen(retu content = data.Id; return content != null; case StandardTableKeyNames.ErrorCodeToolTip: - content = BrowserHelper.GetHelpLinkToolTip(data); + content = (data.GetValidHelpLinkUri() != null) ? string.Format(EditorFeaturesResources.Get_help_for_0, data.Id) : null; return content != null; case StandardTableKeyNames.HelpKeyword: content = data.Id; return content != null; case StandardTableKeyNames.HelpLink: - content = BrowserHelper.GetHelpLink(data)?.AbsoluteUri; + content = data.GetValidHelpLinkUri()?.AbsoluteUri; return content != null; case StandardTableKeyNames.ErrorCategory: content = data.Category; @@ -416,7 +421,7 @@ private string GetBuildTool(string buildTool) return _source.BuildTool; } - private ErrorSource GetErrorSource(string buildTool) + private static ErrorSource GetErrorSource(string buildTool) { if (buildTool == PredefinedBuildTools.Build) { @@ -426,7 +431,7 @@ private ErrorSource GetErrorSource(string buildTool) return ErrorSource.Other; } - private ErrorRank GetErrorRank(DiagnosticData item) + private static ErrorRank GetErrorRank(DiagnosticData item) { if (!item.Properties.TryGetValue(WellKnownDiagnosticPropertyNames.Origin, out var value)) { @@ -571,7 +576,7 @@ public bool TryCreateToolTip(int index, string columnName, [NotNullWhen(returnVa } #pragma warning disable IDE0060 // Remove unused parameter - TODO: remove this once we moved to new drop - public bool TryCreateStringContent(int index, string columnName, bool singleColumnView, [NotNullWhen(returnValue: true)] out string? content) + public static bool TryCreateStringContent(int index, string columnName, bool singleColumnView, [NotNullWhen(returnValue: true)] out string? content) #pragma warning restore IDE0060 // Remove unused parameter { content = null; diff --git a/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseDiagnosticListTable.cs b/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseDiagnosticListTable.cs index a231705be0231..d7d2f6d4ea758 100644 --- a/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseDiagnosticListTable.cs +++ b/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseDiagnosticListTable.cs @@ -34,9 +34,8 @@ protected VisualStudioBaseDiagnosticListTable(Workspace workspace, ITableManager StandardTableColumnDefinitions.DetailsExpander, StandardTableColumnDefinitions.SuppressionState); - public static __VSERRORCATEGORY GetErrorCategory(DiagnosticSeverity severity) + protected static __VSERRORCATEGORY GetErrorCategory(DiagnosticSeverity severity) { - // REVIEW: why is it using old interface for new API? return severity switch { DiagnosticSeverity.Error => __VSERRORCATEGORY.EC_ERROR, diff --git a/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseTodoListTable.cs b/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseTodoListTable.cs index f19633906b706..7f1b16d61dcc4 100644 --- a/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseTodoListTable.cs +++ b/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseTodoListTable.cs @@ -250,7 +250,7 @@ public override bool TryGetValue(int index, string columnName, [NotNullWhen(true } // TODO: Apply location mapping when creating the TODO item (https://github.com/dotnet/roslyn/issues/36217) - private LinePosition GetLineColumn(TodoTableItem item) + private static LinePosition GetLineColumn(TodoTableItem item) { return VisualStudioVenusSpanMappingService.GetAdjustedLineColumn( item.Workspace, diff --git a/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioDiagnosticListTable.BuildTableDataSource.cs b/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioDiagnosticListTable.BuildTableDataSource.cs index a2d8af8bba50d..8ecd4e782c9eb 100644 --- a/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioDiagnosticListTable.BuildTableDataSource.cs +++ b/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioDiagnosticListTable.BuildTableDataSource.cs @@ -10,6 +10,7 @@ using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Shared; using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList; using Microsoft.VisualStudio.Shell.TableManager; @@ -155,13 +156,13 @@ public override bool TryGetValue(int index, string columnName, [NotNullWhen(true content = data.Id; return content != null; case StandardTableKeyNames.ErrorCodeToolTip: - content = BrowserHelper.GetHelpLinkToolTip(data); + content = (data.GetValidHelpLinkUri() != null) ? string.Format(EditorFeaturesResources.Get_help_for_0, data.Id) : null; return content != null; case StandardTableKeyNames.HelpKeyword: content = data.Id; return content != null; case StandardTableKeyNames.HelpLink: - content = BrowserHelper.GetHelpLink(data)?.AbsoluteUri; + content = data.GetValidHelpLinkUri()?.AbsoluteUri; return content != null; case StandardTableKeyNames.ErrorCategory: content = data.Category; @@ -224,7 +225,7 @@ public override bool TryNavigateTo(int index, bool previewTab, bool activate, Ca TryNavigateTo(item.Workspace, documentId, item.GetOriginalPosition(), previewTab, activate, cancellationToken); } - private DocumentId? GetProperDocumentId(DiagnosticTableItem item) + private static DocumentId? GetProperDocumentId(DiagnosticTableItem item) { var documentId = item.DocumentId; var projectId = item.ProjectId; diff --git a/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializer.cs b/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializer.cs index e487304dfe9f5..5db4f4fb2da67 100644 --- a/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializer.cs +++ b/src/VisualStudio/Core/Def/Implementation/TaskList/CommentTaskTokenSerializer.cs @@ -39,7 +39,7 @@ public CommentTaskTokenSerializer( public bool TryFetch(OptionKey optionKey, out object? value) { value = string.Empty; - if (optionKey != TodoCommentOptions.TokenList) + if (optionKey != new OptionKey(TodoCommentOptions.TokenList)) { return false; } @@ -73,7 +73,7 @@ private void OnPropertyChanged(object sender, PropertyChangedEventArgs e) _lastCommentTokenCache = commentString; // let people to know that comment string has changed - _globalOptionService.RefreshOption(TodoCommentOptions.TokenList, _lastCommentTokenCache); + _globalOptionService.RefreshOption(new OptionKey(TodoCommentOptions.TokenList), _lastCommentTokenCache); } private static string GetTaskTokenList(ITaskList? taskList) diff --git a/src/VisualStudio/Core/Def/Implementation/TaskList/ProjectExternalErrorReporter.cs b/src/VisualStudio/Core/Def/Implementation/TaskList/ProjectExternalErrorReporter.cs index 4e199c11a3099..325eccf35ba43 100644 --- a/src/VisualStudio/Core/Def/Implementation/TaskList/ProjectExternalErrorReporter.cs +++ b/src/VisualStudio/Core/Def/Implementation/TaskList/ProjectExternalErrorReporter.cs @@ -291,7 +291,6 @@ private static DiagnosticData GetDiagnosticData( category: WellKnownDiagnosticTags.Build, message: message, title: message, - enuMessageForBingSearch: message, // Unfortunately, there is no way to get ENU text for this since this is an external error. severity: severity, defaultSeverity: severity, isEnabledByDefault: true, diff --git a/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs b/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs index 958e8a144ab19..1da03363892ea 100644 --- a/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs +++ b/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs @@ -187,7 +187,7 @@ private ValueTask ProcessTodoCommentInfosAsync( return ValueTaskFactory.CompletedTask; } - private void AddFilteredInfos( + private static void AddFilteredInfos( ImmutableArray array, ArrayBuilder filteredArray) { diff --git a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs index f71c6d0415b66..1fad69beb7021 100644 --- a/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs +++ b/src/VisualStudio/Core/Def/Implementation/UnusedReferences/RemoveUnusedReferencesCommandHandler.cs @@ -197,7 +197,7 @@ private ImmutableArray GetUnusedReferencesForProject(Solution s return referenceUpdates; } - private void ApplyUnusedReferenceUpdates(Solution solution, string projectFilePath, ImmutableArray referenceUpdates, CancellationToken cancellationToken) + private static void ApplyUnusedReferenceUpdates(Solution solution, string projectFilePath, ImmutableArray referenceUpdates, CancellationToken cancellationToken) { ThreadHelper.JoinableTaskFactory.Run( () => UnusedReferencesRemover.UpdateReferencesAsync(solution, projectFilePath, referenceUpdates, cancellationToken)); diff --git a/src/VisualStudio/Core/Def/Implementation/Venus/ContainedDocument.cs b/src/VisualStudio/Core/Def/Implementation/Venus/ContainedDocument.cs index 8caf624088bc9..bdb97bfb2281a 100644 --- a/src/VisualStudio/Core/Def/Implementation/Venus/ContainedDocument.cs +++ b/src/VisualStudio/Core/Def/Implementation/Venus/ContainedDocument.cs @@ -311,7 +311,7 @@ private IEnumerable FilterTextChanges(SourceText originalText, List< } } - private bool WhitespaceOnEdges(TextSpan visibleTextSpan, TextChange change) + private static bool WhitespaceOnEdges(TextSpan visibleTextSpan, TextChange change) { if (!string.IsNullOrWhiteSpace(change.NewText)) { @@ -347,7 +347,7 @@ private IEnumerable GetSubTextChanges(SourceText originalText, TextC return GetSubTextChanges(originalText, visibleSpanInOriginalText, leftText, rightText, offsetInOriginalText); } - private bool TryGetSubTextChanges( + private static bool TryGetSubTextChanges( SourceText originalText, TextSpan visibleSpanInOriginalText, string leftText, string rightText, int offsetInOriginalText, List changes) { // these are expensive. but hopefully we don't hit this as much except the boundary cases. @@ -407,10 +407,10 @@ private IEnumerable GetSubTextChanges( } } - private bool TryGetWhitespaceOnlyChanges(string leftText, string rightText, List spansInLeftText, List spansInRightText) + private static bool TryGetWhitespaceOnlyChanges(string leftText, string rightText, List spansInLeftText, List spansInRightText) => TryGetWhitespaceGroup(leftText, spansInLeftText) && TryGetWhitespaceGroup(rightText, spansInRightText) && spansInLeftText.Count == spansInRightText.Count; - private bool TryGetWhitespaceGroup(string text, List groups) + private static bool TryGetWhitespaceGroup(string text, List groups) { if (text.Length == 0) { @@ -464,7 +464,7 @@ private bool TryGetWhitespaceGroup(string text, List groups) return true; } - private bool TextAt(string text, int index, char ch1, char ch2 = default) + private static bool TextAt(string text, int index, char ch1, char ch2 = default) { if (index < 0 || text.Length <= index) { @@ -485,7 +485,7 @@ private bool TextAt(string text, int index, char ch1, char ch2 = default) return false; } - private bool TryGetSubTextChange( + private static bool TryGetSubTextChange( SourceText originalText, TextSpan visibleSpanInOriginalText, string rightText, TextSpan spanInOriginalText, TextSpan spanInRightText, out TextChange textChange) { @@ -593,7 +593,7 @@ private IHierarchicalDifferenceCollection DiffStrings(string leftTextWithReplace return diffService.DiffStrings(leftTextWithReplacement, rightTextWithReplacement, s_venusEditOptions.DifferenceOptions); } - private void GetTextWithReplacements( + private static void GetTextWithReplacements( string leftText, string rightText, List> leftReplacementMap, List> rightReplacementMap, out string leftTextWithReplacement, out string rightTextWithReplacement) @@ -625,7 +625,7 @@ private static string GetReplacementStrings(string leftText, string rightText, s } } - private string GetTextWithReplacementMap(string text, string returnReplacement, string newLineReplacement, List> replacementMap) + private static string GetTextWithReplacementMap(string text, string returnReplacement, string newLineReplacement, List> replacementMap) { var delta = 0; var returnLength = returnReplacement.Length; @@ -656,7 +656,7 @@ private string GetTextWithReplacementMap(string text, string returnReplacement, return StringBuilderPool.ReturnAndFree(sb); } - private Span AdjustSpan(Span span, List> replacementMap) + private static Span AdjustSpan(Span span, List> replacementMap) { var start = span.Start; var end = span.End; @@ -866,7 +866,7 @@ public BaseIndentationFormattingRule GetBaseIndentationRule(SyntaxNode root, Sou return new BaseIndentationFormattingRule(root, span, indentation, _vbHelperFormattingRule); } - private void GetVisibleAndTextSpan(SourceText text, List spans, int spanIndex, out TextSpan visibleSpan, out TextSpan visibleTextSpan) + private static void GetVisibleAndTextSpan(SourceText text, List spans, int spanIndex, out TextSpan visibleSpan, out TextSpan visibleTextSpan) { visibleSpan = spans[spanIndex]; @@ -907,7 +907,7 @@ private int GetBaseIndentation(SyntaxNode root, SourceText text, TextSpan span) return additionalIndentation; } - private TextSpan GetVisibleTextSpan(SourceText text, TextSpan visibleSpan, bool uptoFirstAndLastLine = false) + private static TextSpan GetVisibleTextSpan(SourceText text, TextSpan visibleSpan, bool uptoFirstAndLastLine = false) { var start = visibleSpan.Start; for (; start < visibleSpan.End; start++) @@ -1067,7 +1067,7 @@ private bool IsCodeBlock(ITextSnapshot surfaceSnapshot, int position, char ch) return false; } - private bool CheckCode(ITextSnapshot snapshot, int position, char ch, string tag, bool checkAt = true) + private static bool CheckCode(ITextSnapshot snapshot, int position, char ch, string tag, bool checkAt = true) { if (ch != tag[tag.Length - 1] || position < tag.Length) { @@ -1079,7 +1079,7 @@ private bool CheckCode(ITextSnapshot snapshot, int position, char ch, string tag return string.Equals(razorTag, tag, StringComparison.OrdinalIgnoreCase) && (!checkAt || snapshot[start - 1] == RazorExplicit); } - private bool CheckCode(ITextSnapshot snapshot, int position, string tag) + private static bool CheckCode(ITextSnapshot snapshot, int position, string tag) { var i = position - 1; if (i < 0) @@ -1101,7 +1101,7 @@ private bool CheckCode(ITextSnapshot snapshot, int position, string tag) return CheckCode(snapshot, position, ch, tag); } - private bool CheckCode(ITextSnapshot snapshot, int position, char ch, string tag1, string tag2) + private static bool CheckCode(ITextSnapshot snapshot, int position, char ch, string tag1, string tag2) { if (!CheckCode(snapshot, position, ch, tag2, checkAt: false)) { diff --git a/src/VisualStudio/Core/Def/Implementation/VirtualMemoryNotificationListener.cs b/src/VisualStudio/Core/Def/Implementation/VirtualMemoryNotificationListener.cs index 4accbd453df69..16f74311f2e5c 100644 --- a/src/VisualStudio/Core/Def/Implementation/VirtualMemoryNotificationListener.cs +++ b/src/VisualStudio/Core/Def/Implementation/VirtualMemoryNotificationListener.cs @@ -142,7 +142,7 @@ private bool ShouldDisableBackgroundAnalysis(long availableMemory) _globalOptions.GetOption(InternalFeatureOnOffOptions.BackgroundAnalysisMemoryMonitor); } - private void DisableBackgroundAnalysis() + private static void DisableBackgroundAnalysis() { // Force low VM minimal background analysis for the current VS session. SolutionCrawlerOptions.LowMemoryForcedMinimalBackgroundAnalysis = true; diff --git a/src/VisualStudio/Core/Def/Implementation/VsRefactorNotifyService.cs b/src/VisualStudio/Core/Def/Implementation/VsRefactorNotifyService.cs index 7d360f5c7e599..416549b48aaa7 100644 --- a/src/VisualStudio/Core/Def/Implementation/VsRefactorNotifyService.cs +++ b/src/VisualStudio/Core/Def/Implementation/VsRefactorNotifyService.cs @@ -153,7 +153,7 @@ private bool TryGetItemIDsAndRQName( return true; } - private bool TryGetRenamingRQNameForSymbol(ISymbol symbol, out string rqname) + private static bool TryGetRenamingRQNameForSymbol(ISymbol symbol, out string rqname) { if (symbol.Kind == SymbolKind.Method) { diff --git a/src/VisualStudio/Core/Def/Implementation/Watson/FaultReporter.cs b/src/VisualStudio/Core/Def/Implementation/Watson/FaultReporter.cs index 3c5d8ea53dc3d..6f11867c7a558 100644 --- a/src/VisualStudio/Core/Def/Implementation/Watson/FaultReporter.cs +++ b/src/VisualStudio/Core/Def/Implementation/Watson/FaultReporter.cs @@ -27,7 +27,6 @@ internal static class FaultReporter public static void InitializeFatalErrorHandlers() { FatalError.Handler = static (exception, severity, forceDump) => ReportFault(exception, ConvertSeverity(severity), forceDump); - FatalError.HandlerIsNonFatal = true; FatalError.CopyHandlerTo(typeof(Compilation).Assembly); } diff --git a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioFormattingRuleFactoryServiceFactory.cs b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioFormattingRuleFactoryServiceFactory.cs index cc805484e56af..4cf96042f4750 100644 --- a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioFormattingRuleFactoryServiceFactory.cs +++ b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioFormattingRuleFactoryServiceFactory.cs @@ -42,7 +42,7 @@ public bool ShouldUseBaseIndentation(Document document) public bool ShouldNotFormatOrCommitOnPaste(Document document) => IsContainedDocument(document); - private bool IsContainedDocument(Document document) + private static bool IsContainedDocument(Document document) { var visualStudioWorkspace = document.Project.Solution.Workspace as VisualStudioWorkspaceImpl; return visualStudioWorkspace?.TryGetContainedDocument(document.Id) != null; diff --git a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioSymbolNavigationService.cs b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioSymbolNavigationService.cs index f8d7f677a9ba0..b5702ec77ad5c 100644 --- a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioSymbolNavigationService.cs +++ b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioSymbolNavigationService.cs @@ -115,14 +115,22 @@ public bool TryNavigateToSymbol(ISymbol symbol, Project project, OptionSet? opti } // Generate new source or retrieve existing source for the symbol in question + return ThreadingContext.JoinableTaskFactory.Run(() => TryNavigateToMetadataAsync(project, symbol, options, cancellationToken)); + } + + private async Task TryNavigateToMetadataAsync(Project project, ISymbol symbol, OptionSet options, CancellationToken cancellationToken) + { var allowDecompilation = _globalOptions.GetOption(FeatureOnOffOptions.NavigateToDecompiledSources); - var result = ThreadingContext.JoinableTaskFactory.Run(() => _metadataAsSourceFileService.GetGeneratedFileAsync(project, symbol, signaturesOnly: false, allowDecompilation, cancellationToken)); + + var result = await _metadataAsSourceFileService.GetGeneratedFileAsync(project, symbol, signaturesOnly: false, allowDecompilation, cancellationToken).ConfigureAwait(false); + + await this.ThreadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var vsRunningDocumentTable4 = IServiceProviderExtensions.GetService(_serviceProvider); var fileAlreadyOpen = vsRunningDocumentTable4.IsMonikerValid(result.FilePath); var openDocumentService = IServiceProviderExtensions.GetService(_serviceProvider); - openDocumentService.OpenDocumentViaProject(result.FilePath, VSConstants.LOGVIEWID.TextView_guid, out var localServiceProvider, out var hierarchy, out var itemId, out var windowFrame); + openDocumentService.OpenDocumentViaProject(result.FilePath, VSConstants.LOGVIEWID.TextView_guid, out _, out _, out _, out var windowFrame); var documentCookie = vsRunningDocumentTable4.GetDocumentCookie(result.FilePath); diff --git a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioWorkspaceStatusServiceFactory.cs b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioWorkspaceStatusServiceFactory.cs index ad543d0f486ad..40fb9f9bb5736 100644 --- a/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioWorkspaceStatusServiceFactory.cs +++ b/src/VisualStudio/Core/Def/Implementation/Workspace/VisualStudioWorkspaceStatusServiceFactory.cs @@ -188,7 +188,7 @@ internal sealed class Options : IOptionProvider { private const string FeatureName = "VisualStudioWorkspaceStatusService"; - public static readonly Option PartialLoadModeFeatureFlag = new(FeatureName, nameof(PartialLoadModeFeatureFlag), defaultValue: false, + public static readonly Option2 PartialLoadModeFeatureFlag = new(FeatureName, nameof(PartialLoadModeFeatureFlag), defaultValue: false, new FeatureFlagStorageLocation("Roslyn.PartialLoadMode")); ImmutableArray IOptionProvider.Options => ImmutableArray.Create( diff --git a/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs b/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs index 3253218dd95a8..1c9d5d6640910 100644 --- a/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs +++ b/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs @@ -654,7 +654,7 @@ public ImmutableArray GetInstalledVersions(string packageName) return versionsAndSplits.Select(v => v.Version).ToImmutableArray(); } - private int CompareSplit(string[] split1, string[] split2) + private static int CompareSplit(string[] split1, string[] split2) { ThisCanBeCalledOnAnyThread(); diff --git a/src/VisualStudio/Core/Def/PublicAPI.Shipped.txt b/src/VisualStudio/Core/Def/PublicAPI.Shipped.txt index 87c5b7e740e51..f44d3c7c7f839 100644 --- a/src/VisualStudio/Core/Def/PublicAPI.Shipped.txt +++ b/src/VisualStudio/Core/Def/PublicAPI.Shipped.txt @@ -3,6 +3,7 @@ abstract Microsoft.VisualStudio.LanguageServices.VisualStudioWorkspace.GetFileCo abstract Microsoft.VisualStudio.LanguageServices.VisualStudioWorkspace.GetHierarchy(Microsoft.CodeAnalysis.ProjectId projectId) -> Microsoft.VisualStudio.Shell.Interop.IVsHierarchy abstract Microsoft.VisualStudio.LanguageServices.VisualStudioWorkspace.TryFindAllReferences(Microsoft.CodeAnalysis.ISymbol symbol, Microsoft.CodeAnalysis.Project project, System.Threading.CancellationToken cancellationToken) -> bool abstract Microsoft.VisualStudio.LanguageServices.VisualStudioWorkspace.TryGoToDefinition(Microsoft.CodeAnalysis.ISymbol symbol, Microsoft.CodeAnalysis.Project project, System.Threading.CancellationToken cancellationToken) -> bool +abstract Microsoft.VisualStudio.LanguageServices.VisualStudioWorkspace.TryGoToDefinitionAsync(Microsoft.CodeAnalysis.ISymbol symbol, Microsoft.CodeAnalysis.Project project, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task Microsoft.VisualStudio.LanguageServices.Progression.GraphNodeCreation Microsoft.VisualStudio.LanguageServices.RQName Microsoft.VisualStudio.LanguageServices.VisualStudioWorkspace diff --git a/src/VisualStudio/Core/Def/PublicAPI.Unshipped.txt b/src/VisualStudio/Core/Def/PublicAPI.Unshipped.txt index 7111c2ce6f7ca..8b137891791fe 100644 --- a/src/VisualStudio/Core/Def/PublicAPI.Unshipped.txt +++ b/src/VisualStudio/Core/Def/PublicAPI.Unshipped.txt @@ -1 +1 @@ -abstract Microsoft.VisualStudio.LanguageServices.VisualStudioWorkspace.TryGoToDefinitionAsync(Microsoft.CodeAnalysis.ISymbol symbol, Microsoft.CodeAnalysis.Project project, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task + diff --git a/src/VisualStudio/Core/Def/RoslynPackage.cs b/src/VisualStudio/Core/Def/RoslynPackage.cs index 3b8914b47e096..e1d3a27ccf0f1 100644 --- a/src/VisualStudio/Core/Def/RoslynPackage.cs +++ b/src/VisualStudio/Core/Def/RoslynPackage.cs @@ -309,7 +309,7 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } - private void ReportSessionWideTelemetry() + private static void ReportSessionWideTelemetry() { SolutionLogger.ReportTelemetry(); AsyncCompletionLogger.ReportTelemetry(); diff --git a/src/VisualStudio/Core/Def/ServicesVSResources.resx b/src/VisualStudio/Core/Def/ServicesVSResources.resx index 5e006552b86b9..a8028e0281ceb 100644 --- a/src/VisualStudio/Core/Def/ServicesVSResources.resx +++ b/src/VisualStudio/Core/Def/ServicesVSResources.resx @@ -975,6 +975,18 @@ Additional information: {1} Report invalid regular expressions + + Colorize JSON strings + + + Detect and offer editor features for likely JSON strings + + + JSON strings + + + Report invalid JSON strings + Your .editorconfig file might override the local settings configured on this page which only apply to your machine. To configure these settings to travel with your solution use EditorConfig files. More info diff --git a/src/VisualStudio/Core/Def/Shared/VisualStudioImageIdService.cs b/src/VisualStudio/Core/Def/Shared/VisualStudioImageIdService.cs index 787206ffc6377..18ba1a7fde585 100644 --- a/src/VisualStudio/Core/Def/Shared/VisualStudioImageIdService.cs +++ b/src/VisualStudio/Core/Def/Shared/VisualStudioImageIdService.cs @@ -77,7 +77,7 @@ private ImageId GetImageId(ImmutableArray tags) return glyph.GetImageId(); } - private ImageCompositionLayer CreateLayer( + private static ImageCompositionLayer CreateLayer( ImageMoniker imageMoniker, int virtualWidth = 16, int virtualYOffset = 0, diff --git a/src/VisualStudio/Core/Def/SolutionEventMonitor.cs b/src/VisualStudio/Core/Def/SolutionEventMonitor.cs index 5aa58effa87ca..e07a79acde027 100644 --- a/src/VisualStudio/Core/Def/SolutionEventMonitor.cs +++ b/src/VisualStudio/Core/Def/SolutionEventMonitor.cs @@ -19,42 +19,25 @@ internal sealed class SolutionEventMonitor : IDisposable private const string SolutionOpening = "Solution Opening"; private const string SolutionClosing = "Solution Closing"; - private readonly UIContext? _solutionClosingContext; - private IGlobalOperationNotificationService? _notificationService; + private readonly UIContext _solutionClosingContext = UIContext.FromUIContextGuid(VSConstants.UICONTEXT.SolutionClosing_guid); + private readonly IGlobalOperationNotificationService _notificationService; private readonly Dictionary _operations = new(); public SolutionEventMonitor(VisualStudioWorkspace workspace) { - if (workspace.Services.GetService() is GlobalOperationNotificationService notificationService) - { - // subscribe to events only if it is normal service. if it is one from unit test or other, don't bother to subscribe - _notificationService = notificationService; - - // make sure we set initial state correctly. otherwise, we can get into a race where we might miss the very first events - if (KnownUIContexts.SolutionBuildingContext.IsActive) - { - ContextChanged(active: true, operation: SolutionBuilding); - } - - KnownUIContexts.SolutionBuildingContext.UIContextChanged += SolutionBuildingContextChanged; - - // make sure we set initial state correctly. otherwise, we can get into a race where we might miss the very first events - if (KnownUIContexts.SolutionOpeningContext.IsActive) - { - ContextChanged(active: true, operation: SolutionOpening); - } - - KnownUIContexts.SolutionOpeningContext.UIContextChanged += SolutionOpeningContextChanged; + _notificationService = workspace.Services.GetRequiredService(); - _solutionClosingContext = UIContext.FromUIContextGuid(VSConstants.UICONTEXT.SolutionClosing_guid); + RegisterEventHandler(KnownUIContexts.SolutionBuildingContext, SolutionBuildingContextChanged); + RegisterEventHandler(KnownUIContexts.SolutionOpeningContext, SolutionOpeningContextChanged); + RegisterEventHandler(_solutionClosingContext, SolutionClosingContextChanged); + static void RegisterEventHandler(UIContext context, EventHandler handler) + { // make sure we set initial state correctly. otherwise, we can get into a race where we might miss the very first events - if (_solutionClosingContext.IsActive) - { - ContextChanged(active: true, operation: SolutionClosing); - } + if (context.IsActive) + handler(sender: null, UIContextChangedEventArgs.From(activated: true)); - _solutionClosingContext.UIContextChanged += SolutionClosingContextChanged; + context.UIContextChanged += handler; } } @@ -67,33 +50,22 @@ public void Dispose() _operations.Clear(); - if (_notificationService != null) - { - _notificationService = null; - KnownUIContexts.SolutionBuildingContext.UIContextChanged -= SolutionBuildingContextChanged; - KnownUIContexts.SolutionOpeningContext.UIContextChanged -= SolutionOpeningContextChanged; - - if (_solutionClosingContext != null) - _solutionClosingContext.UIContextChanged -= SolutionClosingContextChanged; - } + KnownUIContexts.SolutionBuildingContext.UIContextChanged -= SolutionBuildingContextChanged; + KnownUIContexts.SolutionOpeningContext.UIContextChanged -= SolutionOpeningContextChanged; + _solutionClosingContext.UIContextChanged -= SolutionClosingContextChanged; } - private void SolutionBuildingContextChanged(object sender, UIContextChangedEventArgs e) + private void SolutionBuildingContextChanged(object? sender, UIContextChangedEventArgs e) => ContextChanged(e.Activated, SolutionBuilding); - private void SolutionOpeningContextChanged(object sender, UIContextChangedEventArgs e) + private void SolutionOpeningContextChanged(object? sender, UIContextChangedEventArgs e) => ContextChanged(e.Activated, SolutionOpening); - private void SolutionClosingContextChanged(object sender, UIContextChangedEventArgs e) + private void SolutionClosingContextChanged(object? sender, UIContextChangedEventArgs e) => ContextChanged(e.Activated, SolutionClosing); private void ContextChanged(bool active, string operation) { - if (_notificationService == null) - { - return; - } - TryCancelPendingNotification(operation); if (active) diff --git a/src/VisualStudio/Core/Def/Telemetry/SyntaxTreeConfigurationOptions.cs b/src/VisualStudio/Core/Def/Telemetry/SyntaxTreeConfigurationOptions.cs index d70cef1949bfb..8fbc9f8ad1437 100644 --- a/src/VisualStudio/Core/Def/Telemetry/SyntaxTreeConfigurationOptions.cs +++ b/src/VisualStudio/Core/Def/Telemetry/SyntaxTreeConfigurationOptions.cs @@ -18,11 +18,11 @@ internal class WorkspaceConfigurationOptions : IOptionProvider /// /// Disables if the workspace creates recoverable trees when from its s. /// - public static readonly Option DisableRecoverableTrees = new( + public static readonly Option2 DisableRecoverableTrees = new( nameof(WorkspaceConfigurationOptions), nameof(DisableRecoverableTrees), defaultValue: false, new FeatureFlagStorageLocation("Roslyn.DisableRecoverableTrees")); - public static readonly Option DisableProjectCacheService = new( + public static readonly Option2 DisableProjectCacheService = new( nameof(WorkspaceConfigurationOptions), nameof(DisableProjectCacheService), defaultValue: false, new FeatureFlagStorageLocation("Roslyn.DisableProjectCacheService")); diff --git a/src/VisualStudio/Core/Def/Telemetry/VisualStudioSyntaxTreeConfigurationService.cs b/src/VisualStudio/Core/Def/Telemetry/VisualStudioSyntaxTreeConfigurationService.cs index 362f2871a1b15..31e10e705f76a 100644 --- a/src/VisualStudio/Core/Def/Telemetry/VisualStudioSyntaxTreeConfigurationService.cs +++ b/src/VisualStudio/Core/Def/Telemetry/VisualStudioSyntaxTreeConfigurationService.cs @@ -37,11 +37,11 @@ internal sealed class OptionsMetadata : IOptionProvider /// /// Disables if the workspace creates recoverable trees when from its s. /// - public static readonly Option DisableRecoverableTrees = new( + public static readonly Option2 DisableRecoverableTrees = new( nameof(WorkspaceConfigurationOptions), nameof(DisableRecoverableTrees), defaultValue: false, new FeatureFlagStorageLocation("Roslyn.DisableRecoverableTrees")); - public static readonly Option DisableProjectCacheService = new( + public static readonly Option2 DisableProjectCacheService = new( nameof(WorkspaceConfigurationOptions), nameof(DisableProjectCacheService), defaultValue: false, new FeatureFlagStorageLocation("Roslyn.DisableProjectCacheService")); diff --git a/src/VisualStudio/Core/Def/Telemetry/VisualStudioWorkspaceTelemetryService.cs b/src/VisualStudio/Core/Def/Telemetry/VisualStudioWorkspaceTelemetryService.cs index ae39307317dd4..4f54d35f9b0cb 100644 --- a/src/VisualStudio/Core/Def/Telemetry/VisualStudioWorkspaceTelemetryService.cs +++ b/src/VisualStudio/Core/Def/Telemetry/VisualStudioWorkspaceTelemetryService.cs @@ -5,6 +5,7 @@ using System; using System.Composition; using System.Diagnostics; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host.Mef; @@ -21,24 +22,24 @@ namespace Microsoft.VisualStudio.LanguageServices.Telemetry internal sealed class VisualStudioWorkspaceTelemetryService : AbstractWorkspaceTelemetryService { private readonly VisualStudioWorkspace _workspace; - private readonly IGlobalOptionService _optionsService; + private readonly IGlobalOptionService _globalOptions; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public VisualStudioWorkspaceTelemetryService( VisualStudioWorkspace workspace, - IGlobalOptionService optionsService) + IGlobalOptionService globalOptions) { _workspace = workspace; - _optionsService = optionsService; + _globalOptions = globalOptions; } protected override ILogger CreateLogger(TelemetrySession telemetrySession) => AggregateLogger.Create( CodeMarkerLogger.Instance, - new EtwLogger(_optionsService), + new EtwLogger(FunctionIdOptions.CreateFunctionIsEnabledPredicate(_globalOptions)), new VSTelemetryLogger(telemetrySession), - new FileLogger(_optionsService), + new FileLogger(_globalOptions), Logger.GetLogger()); protected override void TelemetrySessionInitialized() diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf index 91aa6b84acfbc..ce18c664c7f3a 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf @@ -242,6 +242,11 @@ Barevné nápovědy + + Colorize JSON strings + Colorize JSON strings + + Colorize regular expressions Obarvit regulární výrazy @@ -302,6 +307,11 @@ Odvozené typy + + Detect and offer editor features for likely JSON strings + Detect and offer editor features for likely JSON strings + + Disabled Zakázáno @@ -542,6 +552,11 @@ Původ položky + + JSON strings + JSON strings + + Keep Zachovat @@ -1087,6 +1102,11 @@ Přejmenovat {0} na {1} + + Report invalid JSON strings + Report invalid JSON strings + + Report invalid regular expressions Nahlásit neplatné regulární výrazy diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf index 9214803885316..dcd31229b3630 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf @@ -242,6 +242,11 @@ Farbhinweise + + Colorize JSON strings + Colorize JSON strings + + Colorize regular expressions Reguläre Ausdrücke farbig hervorheben @@ -302,6 +307,11 @@ Abgeleitete Typen + + Detect and offer editor features for likely JSON strings + Detect and offer editor features for likely JSON strings + + Disabled Deaktiviert @@ -542,6 +552,11 @@ Elementursprung + + JSON strings + JSON strings + + Keep Beibehalten @@ -1087,6 +1102,11 @@ "{0}" in "{1}" umbenennen + + Report invalid JSON strings + Report invalid JSON strings + + Report invalid regular expressions Ungültige reguläre Ausdrücke melden diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf index 95bdc345a9c42..fc6a0050f606d 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf @@ -242,6 +242,11 @@ Sugerencias de color + + Colorize JSON strings + Colorize JSON strings + + Colorize regular expressions Colorear expresiones regulares @@ -302,6 +307,11 @@ Tipos derivados + + Detect and offer editor features for likely JSON strings + Detect and offer editor features for likely JSON strings + + Disabled Deshabilitado @@ -542,6 +552,11 @@ Origen del elemento + + JSON strings + JSON strings + + Keep Mantener @@ -1087,6 +1102,11 @@ Cambiar nombre de {0} a {1} + + Report invalid JSON strings + Report invalid JSON strings + + Report invalid regular expressions Notificar expresiones regulares no válidas diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf index c2f98dd332ac2..271af67c06a20 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf @@ -242,6 +242,11 @@ Indicateurs de couleurs + + Colorize JSON strings + Colorize JSON strings + + Colorize regular expressions Coloriser les expressions régulières @@ -302,6 +307,11 @@ Types dérivés + + Detect and offer editor features for likely JSON strings + Detect and offer editor features for likely JSON strings + + Disabled Désactivé @@ -542,6 +552,11 @@ Origine de l'élément + + JSON strings + JSON strings + + Keep Conserver @@ -1087,6 +1102,11 @@ Renommer {0} en {1} + + Report invalid JSON strings + Report invalid JSON strings + + Report invalid regular expressions Signaler les expressions régulières non valides diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf index 7e0d381778a7a..dcc20176433a9 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf @@ -242,6 +242,11 @@ Suggerimenti per i colori + + Colorize JSON strings + Colorize JSON strings + + Colorize regular expressions Colora espressioni regolari @@ -302,6 +307,11 @@ Tipi derivati + + Detect and offer editor features for likely JSON strings + Detect and offer editor features for likely JSON strings + + Disabled Disabilitato @@ -542,6 +552,11 @@ Origine dell'elemento + + JSON strings + JSON strings + + Keep Mantieni @@ -1087,6 +1102,11 @@ Rinomina {0} in {1} + + Report invalid JSON strings + Report invalid JSON strings + + Report invalid regular expressions Segnala espressioni regolari non valide diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf index b3100a936ca46..5cc1fee1cdb24 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf @@ -242,6 +242,11 @@ 色のヒント + + Colorize JSON strings + Colorize JSON strings + + Colorize regular expressions 正規表現をカラー化 @@ -302,6 +307,11 @@ 派生型 + + Detect and offer editor features for likely JSON strings + Detect and offer editor features for likely JSON strings + + Disabled 無効 @@ -542,6 +552,11 @@ 項目の送信元 + + JSON strings + JSON strings + + Keep 保持 @@ -1087,6 +1102,11 @@ {0} の名前を {1} に変更 + + Report invalid JSON strings + Report invalid JSON strings + + Report invalid regular expressions 無効な正規表現を報告 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf index 1db9539ee2c27..9dace5855a469 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf @@ -242,6 +242,11 @@ 색 힌트 + + Colorize JSON strings + Colorize JSON strings + + Colorize regular expressions 정규식 색 지정 @@ -302,6 +307,11 @@ 파생 형식 + + Detect and offer editor features for likely JSON strings + Detect and offer editor features for likely JSON strings + + Disabled 사용 안 함 @@ -542,6 +552,11 @@ 항목 원본 + + JSON strings + JSON strings + + Keep 유지 @@ -1087,6 +1102,11 @@ {0} 이름을 {1}(으)로 바꾸기 + + Report invalid JSON strings + Report invalid JSON strings + + Report invalid regular expressions 잘못된 정규식 보고 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf index a143d4c773a03..5193dcb7cd8f5 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf @@ -242,6 +242,11 @@ Wskazówki kolorów + + Colorize JSON strings + Colorize JSON strings + + Colorize regular expressions Koloruj wyrażenia regularne @@ -302,6 +307,11 @@ Typy pochodne + + Detect and offer editor features for likely JSON strings + Detect and offer editor features for likely JSON strings + + Disabled Wyłączone @@ -542,6 +552,11 @@ Źródło elementu + + JSON strings + JSON strings + + Keep Zachowaj @@ -1087,6 +1102,11 @@ Zmień nazwę {0} na {1} + + Report invalid JSON strings + Report invalid JSON strings + + Report invalid regular expressions Raportuj nieprawidłowe wyrażenia regularne diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf index 4197537e2a0d9..7cb92b618af5a 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf @@ -242,6 +242,11 @@ Dicas com cores + + Colorize JSON strings + Colorize JSON strings + + Colorize regular expressions Colorir expressões regulares @@ -302,6 +307,11 @@ Tipos derivados + + Detect and offer editor features for likely JSON strings + Detect and offer editor features for likely JSON strings + + Disabled Desabilitado @@ -542,6 +552,11 @@ Origem do item + + JSON strings + JSON strings + + Keep Manter @@ -1087,6 +1102,11 @@ Renomear {0} para {1} + + Report invalid JSON strings + Report invalid JSON strings + + Report invalid regular expressions Relatar expressões regulares inválidas diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf index 19f9a6da16b0a..cabef39b3f666 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf @@ -242,6 +242,11 @@ Цветовые подсказки + + Colorize JSON strings + Colorize JSON strings + + Colorize regular expressions Выделить регулярные выражения цветом @@ -302,6 +307,11 @@ Производные типы + + Detect and offer editor features for likely JSON strings + Detect and offer editor features for likely JSON strings + + Disabled Отключено @@ -542,6 +552,11 @@ Источник элемента + + JSON strings + JSON strings + + Keep Сохранить @@ -1087,6 +1102,11 @@ Переименовать {0} в {1} + + Report invalid JSON strings + Report invalid JSON strings + + Report invalid regular expressions Сообщать о недопустимых регулярных выражениях diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf index b85e07a628f81..ad17f6363e6b9 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf @@ -242,6 +242,11 @@ Renk ipuçları + + Colorize JSON strings + Colorize JSON strings + + Colorize regular expressions Normal ifadeleri renklendir @@ -302,6 +307,11 @@ Türetilmiş türler + + Detect and offer editor features for likely JSON strings + Detect and offer editor features for likely JSON strings + + Disabled Devre dışı @@ -542,6 +552,11 @@ Öğe çıkış noktası + + JSON strings + JSON strings + + Keep Koru @@ -1087,6 +1102,11 @@ {0} öğesini {1} olarak yeniden adlandır + + Report invalid JSON strings + Report invalid JSON strings + + Report invalid regular expressions Geçersiz normal ifadeleri bildir diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf index c2ac3476cd0d5..2a8e2b0012fa1 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf @@ -242,6 +242,11 @@ 颜色提示 + + Colorize JSON strings + Colorize JSON strings + + Colorize regular expressions 为正规表达式着色 @@ -302,6 +307,11 @@ 派生类型 + + Detect and offer editor features for likely JSON strings + Detect and offer editor features for likely JSON strings + + Disabled 已禁用 @@ -542,6 +552,11 @@ 项来源 + + JSON strings + JSON strings + + Keep 保留 @@ -1087,6 +1102,11 @@ 将 {0} 重命名为 {1} + + Report invalid JSON strings + Report invalid JSON strings + + Report invalid regular expressions 报告无效的正规表达式 diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf index 4ec614b139bc2..f0f99cdfa3b6f 100644 --- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf +++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf @@ -242,6 +242,11 @@ 色彩提示 + + Colorize JSON strings + Colorize JSON strings + + Colorize regular expressions 為規則運算式添加色彩 @@ -302,6 +307,11 @@ 衍生類型 + + Detect and offer editor features for likely JSON strings + Detect and offer editor features for likely JSON strings + + Disabled 已停用 @@ -542,6 +552,11 @@ 項目原點 + + JSON strings + JSON strings + + Keep 保留 @@ -1087,6 +1102,11 @@ 將 {0} 重新命名為 {1} + + Report invalid JSON strings + Report invalid JSON strings + + Report invalid regular expressions 回報無效的規則運算式 diff --git a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs index 0e496a9538361..7c0fe635a43ea 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelService.cs @@ -1001,16 +1001,16 @@ private int GetMemberInsertionIndex(SyntaxNode container, int insertionIndex) } } - private int GetAttributeArgumentInsertionIndex(int insertionIndex) + private static int GetAttributeArgumentInsertionIndex(int insertionIndex) => insertionIndex; - private int GetAttributeInsertionIndex(int insertionIndex) + private static int GetAttributeInsertionIndex(int insertionIndex) => insertionIndex; - private int GetImportInsertionIndex(int insertionIndex) + private static int GetImportInsertionIndex(int insertionIndex) => insertionIndex; - private int GetParameterInsertionIndex(int insertionIndex) + private static int GetParameterInsertionIndex(int insertionIndex) => insertionIndex; protected abstract bool IsCodeModelNode(SyntaxNode node); diff --git a/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel_Events.cs b/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel_Events.cs index 8331e1ae3f8ac..50260b379eeed 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel_Events.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/FileCodeModel_Events.cs @@ -96,7 +96,7 @@ public void FireEvents() return; } - private EnvDTE80.vsCMChangeKind ConvertToChangeKind(CodeModelEventType eventType) + private static EnvDTE80.vsCMChangeKind ConvertToChangeKind(CodeModelEventType eventType) { EnvDTE80.vsCMChangeKind result = 0; diff --git a/src/VisualStudio/Core/Impl/CodeModel/MethodXml/AbstractMethodXmlBuilder.cs b/src/VisualStudio/Core/Impl/CodeModel/MethodXml/AbstractMethodXmlBuilder.cs index e1cf14a460ce0..ec5654f2cd1ea 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/MethodXml/AbstractMethodXmlBuilder.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/MethodXml/AbstractMethodXmlBuilder.cs @@ -163,7 +163,7 @@ private static string GetVariableKindText(VariableKind kind) private IDisposable Tag(string name, params AttributeInfo[] attributes) => new AutoTag(this, name, attributes); - private AttributeInfo BinaryOperatorAttribute(BinaryOperatorKind kind) + private static AttributeInfo BinaryOperatorAttribute(BinaryOperatorKind kind) { if (kind == BinaryOperatorKind.None) { @@ -173,7 +173,7 @@ private AttributeInfo BinaryOperatorAttribute(BinaryOperatorKind kind) return new AttributeInfo(BinaryOperatorAttributeName, GetBinaryOperatorKindText(kind)); } - private AttributeInfo FullNameAttribute(string name) + private static AttributeInfo FullNameAttribute(string name) { if (string.IsNullOrWhiteSpace(name)) { @@ -183,7 +183,7 @@ private AttributeInfo FullNameAttribute(string name) return new AttributeInfo(FullNameAttributeName, name); } - private AttributeInfo ImplicitAttribute(bool? @implicit) + private static AttributeInfo ImplicitAttribute(bool? @implicit) { if (@implicit == null) { @@ -193,10 +193,10 @@ private AttributeInfo ImplicitAttribute(bool? @implicit) return new AttributeInfo(ImplicitAttributeName, @implicit.Value ? "yes" : "no"); } - private AttributeInfo LineNumberAttribute(int lineNumber) + private static AttributeInfo LineNumberAttribute(int lineNumber) => new AttributeInfo(LineAttributeName, lineNumber.ToString()); - private AttributeInfo NameAttribute(string name) + private static AttributeInfo NameAttribute(string name) { if (string.IsNullOrWhiteSpace(name)) { @@ -206,10 +206,10 @@ private AttributeInfo NameAttribute(string name) return new AttributeInfo(NameAttributeName, name); } - private AttributeInfo RankAttribute(int rank) + private static AttributeInfo RankAttribute(int rank) => new AttributeInfo(RankAttributeName, rank.ToString()); - private AttributeInfo SpecialCastKindAttribute(SpecialCastKind? specialCastKind = null) + private static AttributeInfo SpecialCastKindAttribute(SpecialCastKind? specialCastKind = null) => specialCastKind switch { SpecialCastKind.DirectCast => new AttributeInfo(DirectCastAttributeName, "yes"), @@ -217,7 +217,7 @@ private AttributeInfo SpecialCastKindAttribute(SpecialCastKind? specialCastKind _ => AttributeInfo.Empty, }; - private AttributeInfo TypeAttribute(string typeName) + private static AttributeInfo TypeAttribute(string typeName) { if (string.IsNullOrWhiteSpace(typeName)) { @@ -227,7 +227,7 @@ private AttributeInfo TypeAttribute(string typeName) return new AttributeInfo(TypeAttributeName, typeName); } - private AttributeInfo VariableKindAttribute(VariableKind kind) + private static AttributeInfo VariableKindAttribute(VariableKind kind) { if (kind == VariableKind.None) { diff --git a/src/VisualStudio/Core/Impl/Options/RadioButtonViewModel.cs b/src/VisualStudio/Core/Impl/Options/RadioButtonViewModel.cs index 362ecafb809bf..834b88b85f052 100644 --- a/src/VisualStudio/Core/Impl/Options/RadioButtonViewModel.cs +++ b/src/VisualStudio/Core/Impl/Options/RadioButtonViewModel.cs @@ -10,10 +10,10 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Options { internal class RadioButtonViewModel : AbstractRadioButtonViewModel { - private readonly Option _option; + private readonly Option2 _option; private readonly TOption _value; - public RadioButtonViewModel(string description, string preview, string group, TOption value, Option option, AbstractOptionPreviewViewModel info, OptionStore optionStore) + public RadioButtonViewModel(string description, string preview, string group, TOption value, Option2 option, AbstractOptionPreviewViewModel info, OptionStore optionStore) : base(description, preview, info, isChecked: optionStore.GetOption(option).Equals(value), group: group) { _value = value; diff --git a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/SymbolSpecificationDialog.xaml.cs b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/SymbolSpecificationDialog.xaml.cs index f6197365cd315..e84f78dcda60d 100644 --- a/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/SymbolSpecificationDialog.xaml.cs +++ b/src/VisualStudio/Core/Impl/Options/Style/NamingPreferences/SymbolSpecification/SymbolSpecificationDialog.xaml.cs @@ -63,7 +63,7 @@ internal SymbolSpecificationDialog(SymbolSpecificationViewModel viewModel) #pragma warning restore } - private AutomationDelegatingListView CreateAutomationDelegatingListView(string itemsSourceName) + private static AutomationDelegatingListView CreateAutomationDelegatingListView(string itemsSourceName) { var listView = new AutomationDelegatingListView(); listView.SelectionMode = SelectionMode.Extended; @@ -81,7 +81,7 @@ private void HandleAccessibilitiesPreviewKeyDown(object sender, KeyEventArgs e) private void HandleModifiersPreviewKeyDown(object sender, KeyEventArgs e) => HandlePreviewKeyDown(e, modifiersListView.SelectedItems.OfType()); - private void HandlePreviewKeyDown(KeyEventArgs e, IEnumerable selectedItems) where T : SymbolSpecificationViewModel.ISymbolSpecificationViewModelPart + private static void HandlePreviewKeyDown(KeyEventArgs e, IEnumerable selectedItems) where T : SymbolSpecificationViewModel.ISymbolSpecificationViewModelPart { if (e.Key == Key.Space) { diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItemTracker.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItemTracker.cs index 8193347354083..d786d06ae5491 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItemTracker.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzerItemTracker.cs @@ -112,7 +112,7 @@ int IVsSelectionEvents.OnSelectionChanged( return VSConstants.S_OK; } - private object[] GetSelectedObjects(ISelectionContainer? selectionContainer) + private static object[] GetSelectedObjects(ISelectionContainer? selectionContainer) { if (selectionContainer == null) { diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersCommandHandler.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersCommandHandler.cs index 2cc73c7d6c73c..6eb00cea5c3c7 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersCommandHandler.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/AnalyzersCommandHandler.cs @@ -226,7 +226,7 @@ private void UpdateDiagnosticContextMenu() UpdateOpenHelpLinkMenuItemVisibility(); } - private MenuCommand AddCommandHandler(IMenuCommandService menuCommandService, int roslynCommand, EventHandler handler) + private static MenuCommand AddCommandHandler(IMenuCommandService menuCommandService, int roslynCommand, EventHandler handler) { var commandID = new CommandID(Guids.RoslynGroupId, roslynCommand); var menuCommand = new MenuCommand(handler, commandID); @@ -262,7 +262,7 @@ private void UpdateOtherMenuItemsEnabled() private void UpdateOpenHelpLinkMenuItemVisibility() { _openHelpLinkMenuItem.Visible = _tracker.SelectedDiagnosticItems.Length == 1 && - _tracker.SelectedDiagnosticItems[0].GetHelpLink() != null; + _tracker.SelectedDiagnosticItems[0].Descriptor.GetValidHelpLinkUri() != null; } private void UpdateSeverityMenuItemsChecked() @@ -534,7 +534,7 @@ private void OpenDiagnosticHelpLinkHandler(object sender, EventArgs e) return; } - var uri = _tracker.SelectedDiagnosticItems[0].GetHelpLink(); + var uri = _tracker.SelectedDiagnosticItems[0].Descriptor.GetValidHelpLinkUri(); if (uri != null) { VisualStudioNavigateToLinkService.StartBrowser(uri); @@ -553,7 +553,7 @@ private void SetActiveRuleSetHandler(object sender, EventArgs e) } } - private string CreateCopyOfRuleSetForProject(string pathToRuleSet, EnvDTE.Project envDteProject) + private static string CreateCopyOfRuleSetForProject(string pathToRuleSet, EnvDTE.Project envDteProject) { var fileName = GetNewRuleSetFileNameForProject(envDteProject); var projectDirectory = Path.GetDirectoryName(envDteProject.FullName); @@ -565,7 +565,7 @@ private string CreateCopyOfRuleSetForProject(string pathToRuleSet, EnvDTE.Projec return fullFilePath; } - private void UpdateProjectConfigurationsToUseRuleSetFile(EnvDTE.Project envDteProject, string fileName) + private static void UpdateProjectConfigurationsToUseRuleSetFile(EnvDTE.Project envDteProject, string fileName) { foreach (EnvDTE.Configuration config in envDteProject.ConfigurationManager) { @@ -589,7 +589,7 @@ private void UpdateProjectConfigurationsToUseRuleSetFile(EnvDTE.Project envDtePr } } - private string GetNewRuleSetFileNameForProject(EnvDTE.Project envDteProject) + private static string GetNewRuleSetFileNameForProject(EnvDTE.Project envDteProject) { var projectName = envDteProject.Name; @@ -658,7 +658,7 @@ private string GetNewRuleSetFileNameForProject(EnvDTE.Project envDteProject) return selectedAction; } - private void SendUnableToOpenRuleSetNotification(Workspace workspace, string message) + private static void SendUnableToOpenRuleSetNotification(Workspace workspace, string message) { SendErrorNotification( workspace, @@ -666,7 +666,7 @@ private void SendUnableToOpenRuleSetNotification(Workspace workspace, string mes message); } - private void SendErrorNotification(Workspace workspace, string message1, string message2) + private static void SendErrorNotification(Workspace workspace, string message1, string message2) { var notificationService = workspace.Services.GetService(); diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/BaseDiagnosticAndGeneratorItemSource.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/BaseDiagnosticAndGeneratorItemSource.cs index ae74220a55882..621c689c63e31 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/BaseDiagnosticAndGeneratorItemSource.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/BaseDiagnosticAndGeneratorItemSource.cs @@ -118,7 +118,7 @@ private BulkObservableCollection CreateDiagnosticAndGeneratorItems(Pro { var selectedDiagnostic = g.OrderBy(d => d, s_comparer).First(); var effectiveSeverity = selectedDiagnostic.GetEffectiveSeverity(options, analyzerConfigOptions); - return new DiagnosticItem(projectId, AnalyzerReference, selectedDiagnostic, effectiveSeverity, language, CommandHandler); + return new DiagnosticItem(projectId, AnalyzerReference, selectedDiagnostic, effectiveSeverity, CommandHandler); })); collection.AddRange( diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.BrowseObject.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.BrowseObject.cs index f945e732e7fee..a39fb894b4c77 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.BrowseObject.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.BrowseObject.cs @@ -6,6 +6,7 @@ using System.ComponentModel; using System.Globalization; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer @@ -53,7 +54,7 @@ public string? HelpLink { get { - return _diagnosticItem.GetHelpLink()?.AbsoluteUri; + return _diagnosticItem.Descriptor.GetValidHelpLinkUri()?.AbsoluteUri; } } @@ -127,7 +128,7 @@ public DiagnosticItem DiagnosticItem get { return _diagnosticItem; } } - private string MapDiagnosticSeverityToText(DiagnosticSeverity severity) + private static string MapDiagnosticSeverityToText(DiagnosticSeverity severity) => severity switch { DiagnosticSeverity.Hidden => SolutionExplorerShim.Hidden, @@ -137,7 +138,7 @@ private string MapDiagnosticSeverityToText(DiagnosticSeverity severity) _ => throw ExceptionUtilities.UnexpectedValue(severity), }; - private string MapReportDiagnosticToText(ReportDiagnostic report) + private static string MapReportDiagnosticToText(ReportDiagnostic report) => report switch { ReportDiagnostic.Default => SolutionExplorerShim.Default_, diff --git a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.cs b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.cs index 32fde5616732a..7ca0230c5b46a 100644 --- a/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.cs +++ b/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/DiagnosticItem.cs @@ -10,11 +10,9 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes.Configuration; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Editor.Shared; using Microsoft.Internal.VisualStudio.PlatformUI; using Microsoft.VisualStudio.Imaging; using Microsoft.VisualStudio.Imaging.Interop; -using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer { @@ -22,7 +20,6 @@ internal partial class DiagnosticItem : BaseItem { private readonly AnalyzerReference _analyzerReference; private readonly IAnalyzersCommandHandler _commandHandler; - private readonly string _language; public ProjectId ProjectId { get; } public DiagnosticDescriptor Descriptor { get; } @@ -30,14 +27,13 @@ internal partial class DiagnosticItem : BaseItem public override event PropertyChangedEventHandler? PropertyChanged; - public DiagnosticItem(ProjectId projectId, AnalyzerReference analyzerReference, DiagnosticDescriptor descriptor, ReportDiagnostic effectiveSeverity, string language, IAnalyzersCommandHandler commandHandler) + public DiagnosticItem(ProjectId projectId, AnalyzerReference analyzerReference, DiagnosticDescriptor descriptor, ReportDiagnostic effectiveSeverity, IAnalyzersCommandHandler commandHandler) : base(descriptor.Id + ": " + descriptor.Title) { ProjectId = projectId; _analyzerReference = analyzerReference; Descriptor = descriptor; EffectiveSeverity = effectiveSeverity; - _language = language; _commandHandler = commandHandler; } @@ -51,9 +47,6 @@ public override object GetBrowseObject() return new BrowseObject(this); } - public Uri? GetHelpLink() - => BrowserHelper.GetHelpLink(Descriptor, _language); - internal void UpdateEffectiveSeverity(ReportDiagnostic newEffectiveSeverity) { if (EffectiveSeverity != newEffectiveSeverity) @@ -65,7 +58,7 @@ internal void UpdateEffectiveSeverity(ReportDiagnostic newEffectiveSeverity) } } - private ImageMoniker MapEffectiveSeverityToIconMoniker(ReportDiagnostic effectiveSeverity) + private static ImageMoniker MapEffectiveSeverityToIconMoniker(ReportDiagnostic effectiveSeverity) => effectiveSeverity switch { ReportDiagnostic.Error => KnownMonikers.CodeErrorRule, diff --git a/src/VisualStudio/Core/Test.Next/Remote/RemoteHostClientServiceFactoryTests.cs b/src/VisualStudio/Core/Test.Next/Remote/RemoteHostClientServiceFactoryTests.cs index 9a274d74b233b..521d2ab98e452 100644 --- a/src/VisualStudio/Core/Test.Next/Remote/RemoteHostClientServiceFactoryTests.cs +++ b/src/VisualStudio/Core/Test.Next/Remote/RemoteHostClientServiceFactoryTests.cs @@ -40,7 +40,7 @@ public async Task UpdaterService() var listenerProvider = exportProvider.GetExportedValue(); var globalOptions = exportProvider.GetExportedValue(); - globalOptions.SetGlobalOption(RemoteHostOptions.SolutionChecksumMonitorBackOffTimeSpanInMS, 1); + globalOptions.SetGlobalOption(new OptionKey(RemoteHostOptions.SolutionChecksumMonitorBackOffTimeSpanInMS), 1); var checksumUpdater = new SolutionChecksumUpdater(workspace, globalOptions, listenerProvider, CancellationToken.None); var service = workspace.Services.GetRequiredService(); diff --git a/src/VisualStudio/Core/Test.Next/Services/AssetProviderTests.cs b/src/VisualStudio/Core/Test.Next/Services/AssetProviderTests.cs index 76f206cfe8b54..3e779c17b4fd6 100644 --- a/src/VisualStudio/Core/Test.Next/Services/AssetProviderTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/AssetProviderTests.cs @@ -39,7 +39,7 @@ public async Task TestVisualBasicParseOptionsSynchronization() await TestAssetAsync(Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions.Default); } - private async Task TestAssetAsync(object data) + private static async Task TestAssetAsync(object data) { var sessionId = 0; var checksum = Checksum.Create(ImmutableArray.CreateRange(Guid.NewGuid().ToByteArray())); diff --git a/src/VisualStudio/Core/Test.Next/Services/LspDiagnosticsTests.cs b/src/VisualStudio/Core/Test.Next/Services/LspDiagnosticsTests.cs deleted file mode 100644 index 5807417ef27d9..0000000000000 --- a/src/VisualStudio/Core/Test.Next/Services/LspDiagnosticsTests.cs +++ /dev/null @@ -1,633 +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.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Editor.Implementation.LanguageClient; -using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; -using Microsoft.CodeAnalysis.LanguageServer; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Shared.TestHooks; -using Microsoft.CodeAnalysis.Test.Utilities; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.LanguageServices.Implementation.LanguageClient; -using Microsoft.VisualStudio.Threading; -using Moq; -using Nerdbank.Streams; -using Newtonsoft.Json.Linq; -using Roslyn.Test.Utilities; -using Roslyn.Utilities; -using StreamJsonRpc; -using Xunit; -using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; - -namespace Roslyn.VisualStudio.Next.UnitTests.Services -{ - [UseExportProvider] - public class LspDiagnosticsTests : AbstractLanguageServerProtocolTests - { - [Fact] - public async Task AddDiagnosticTestAsync() - { - using var server = await CreateTestLspServerAsync(""); - var workspace = server.TestWorkspace; - var document = workspace.CurrentSolution.Projects.First().Documents.First(); - - var diagnosticsMock = new Mock(MockBehavior.Strict); - // Create a mock that returns a diagnostic for the document. - SetupMockWithDiagnostics(diagnosticsMock, document.Id, await CreateMockDiagnosticDataAsync(document, "id").ConfigureAwait(false)); - - // Publish one document change diagnostic notification -> - // 1. doc1 with id. - // - // We expect one publish diagnostic notification -> - // 1. from doc1 with id. - var (testAccessor, results) = await RunPublishDiagnosticsAsync(workspace, diagnosticsMock.Object, 1, document).ConfigureAwait(false); - - var result = Assert.Single(results); - Assert.Equal(new Uri(document.FilePath), result.Uri); - Assert.Equal("id", result.Diagnostics.Single().Code); - } - - [Fact] - public async Task NoDiagnosticsWhenInPullMode() - { - using var server = await CreateTestLspServerAsync(""); - var workspace = server.TestWorkspace; - workspace.SetOptions(workspace.Options.WithChangedOption( - InternalDiagnosticsOptions.NormalDiagnosticMode, DiagnosticMode.Pull)); - - var document = workspace.CurrentSolution.Projects.First().Documents.First(); - - var diagnosticsMock = new Mock(MockBehavior.Strict); - // Create a mock that returns a diagnostic for the document. - SetupMockWithDiagnostics(diagnosticsMock, document.Id, await CreateMockDiagnosticDataAsync(document, "id").ConfigureAwait(false)); - - var (testAccessor, results) = await RunPublishDiagnosticsAsync(workspace, diagnosticsMock.Object, 0, document).ConfigureAwait(false); - Assert.Empty(results); - } - - [Fact] - public async Task AddDiagnosticWithMappedFilesTestAsync() - { - using var server = await CreateTestLspServerAsync(""); - var workspace = server.TestWorkspace; - var document = workspace.CurrentSolution.Projects.First().Documents.First(); - - var diagnosticsMock = new Mock(MockBehavior.Strict); - // Create two mapped diagnostics for the document. - SetupMockWithDiagnostics(diagnosticsMock, document.Id, - await CreateMockDiagnosticDatasWithMappedLocationAsync(document, ("id1", document.FilePath + "m1"), ("id2", document.FilePath + "m2")).ConfigureAwait(false)); - - // Publish one document change diagnostic notification -> - // 1. doc1 with id1 = mapped file m1 and id2 = mapped file m2. - // - // We expect two publish diagnostic notifications -> - // 1. from m1 with id1 (from 1 above). - // 2. from m2 with id2 (from 1 above). - var (testAccessor, results) = await RunPublishDiagnosticsAsync(workspace, diagnosticsMock.Object, expectedNumberOfCallbacks: 2, document).ConfigureAwait(false); - - Assert.Equal(2, results.Count); - Assert.Equal(new Uri(document.FilePath + "m1"), results[0].Uri); - Assert.Equal("id1", results[0].Diagnostics.Single().Code); - - Assert.Equal(new Uri(document.FilePath + "m2"), results[1].Uri); - Assert.Equal("id2", results[1].Diagnostics.Single().Code); - } - - [Fact] - public async Task AddDiagnosticWithMappedFileToManyDocumentsTestAsync() - { - using var server = await CreateTestLspServerAsync(new string[] { "", "" }); - var workspace = server.TestWorkspace; - var documents = workspace.CurrentSolution.Projects.First().Documents.ToImmutableArray(); - - var diagnosticsMock = new Mock(MockBehavior.Strict); - // Create diagnostic for the first document that has a mapped location. - var mappedFilePath = documents[0].FilePath + "m1"; - var documentOneDiagnostic = await CreateMockDiagnosticDatasWithMappedLocationAsync(documents[0], ("doc1Diagnostic", mappedFilePath)).ConfigureAwait(false); - // Create diagnostic for the second document that maps to the same location as the first document diagnostic. - var documentTwoDiagnostic = await CreateMockDiagnosticDatasWithMappedLocationAsync(documents[1], ("doc2Diagnostic", mappedFilePath)).ConfigureAwait(false); - - SetupMockWithDiagnostics(diagnosticsMock, documents[0].Id, documentOneDiagnostic); - SetupMockWithDiagnostics(diagnosticsMock, documents[1].Id, documentTwoDiagnostic); - - // Publish two document change diagnostic notifications -> - // 1. doc1 with doc1Diagnostic = mapped file m1. - // 2. doc2 with doc2Diagnostic = mapped file m1. - // - // We expect two publish diagnostic notifications -> - // 1. from m1 with doc1Diagnostic (from 1 above). - // 2. from m1 with doc1Diagnostic and doc2Diagnostic (from 2 above adding doc2Diagnostic to m1). - var (testAccessor, results) = await RunPublishDiagnosticsAsync(workspace, diagnosticsMock.Object, 2, documents[0], documents[1]).ConfigureAwait(false); - - Assert.Equal(2, results.Count); - var expectedUri = new Uri(mappedFilePath); - Assert.Equal(expectedUri, results[0].Uri); - Assert.Equal("doc1Diagnostic", results[0].Diagnostics.Single().Code); - - Assert.Equal(expectedUri, results[1].Uri); - Assert.Equal(2, results[1].Diagnostics.Length); - Assert.Contains(results[1].Diagnostics, d => d.Code == "doc1Diagnostic"); - Assert.Contains(results[1].Diagnostics, d => d.Code == "doc2Diagnostic"); - } - - [Fact] - public async Task RemoveDiagnosticTestAsync() - { - using var server = await CreateTestLspServerAsync(""); - var workspace = server.TestWorkspace; - var document = workspace.CurrentSolution.Projects.First().Documents.First(); - - var diagnosticsMock = new Mock(MockBehavior.Strict); - // Setup the mock so the first call for a document returns a diagnostic, but the second returns empty. - SetupMockDiagnosticSequence(diagnosticsMock, document.Id, - await CreateMockDiagnosticDataAsync(document, "id").ConfigureAwait(false), - ImmutableArray.Empty); - - // Publish two document change diagnostic notifications -> - // 1. doc1 with id. - // 2. doc1 with empty. - // - // We expect two publish diagnostic notifications -> - // 1. from doc1 with id. - // 2. from doc1 with empty (from 2 above clearing out diagnostics from doc1). - var (testAccessor, results) = await RunPublishDiagnosticsAsync(workspace, diagnosticsMock.Object, 2, document, document).ConfigureAwait(false); - - Assert.Equal(2, results.Count); - Assert.Equal(new Uri(document.FilePath), results[0].Uri); - Assert.Equal("id", results[0].Diagnostics.Single().Code); - - Assert.Equal(new Uri(document.FilePath), results[1].Uri); - Assert.True(results[1].Diagnostics.IsEmpty()); - - Assert.Empty(testAccessor.GetDocumentIdsInPublishedUris()); - Assert.Empty(testAccessor.GetFileUrisInPublishDiagnostics()); - } - - [Fact] - public async Task RemoveDiagnosticForMappedFilesTestAsync() - { - using var server = await CreateTestLspServerAsync(""); - var workspace = server.TestWorkspace; - var document = workspace.CurrentSolution.Projects.First().Documents.First(); - - var diagnosticsMock = new Mock(MockBehavior.Strict); - - var mappedFilePathM1 = document.FilePath + "m1"; - var mappedFilePathM2 = document.FilePath + "m2"; - // Create two mapped diagnostics for the document on first call. - // On the second call, return only the second mapped diagnostic for the document. - SetupMockDiagnosticSequence(diagnosticsMock, document.Id, - await CreateMockDiagnosticDatasWithMappedLocationAsync(document, ("id1", mappedFilePathM1), ("id2", mappedFilePathM2)).ConfigureAwait(false), - await CreateMockDiagnosticDatasWithMappedLocationAsync(document, ("id2", mappedFilePathM2)).ConfigureAwait(false)); - - // Publish three document change diagnostic notifications -> - // 1. doc1 with id1 = mapped file m1 and id2 = mapped file m2. - // 2. doc1 with just id2 = mapped file m2. - // - // We expect four publish diagnostic notifications -> - // 1. from m1 with id1 (from 1 above). - // 2. from m2 with id2 (from 1 above). - // 3. from m1 with empty (from 2 above clearing out diagnostics for m1). - // 4. from m2 with id2 (from 2 above clearing out diagnostics for m1). - var (testAccessor, results) = await RunPublishDiagnosticsAsync(workspace, diagnosticsMock.Object, 4, document, document).ConfigureAwait(false); - - var mappedFileURIM1 = new Uri(mappedFilePathM1); - var mappedFileURIM2 = new Uri(mappedFilePathM2); - - Assert.Equal(4, results.Count); - - // First document update. - Assert.Equal(mappedFileURIM1, results[0].Uri); - Assert.Equal("id1", results[0].Diagnostics.Single().Code); - - Assert.Equal(mappedFileURIM2, results[1].Uri); - Assert.Equal("id2", results[1].Diagnostics.Single().Code); - - // Second document update. - Assert.Equal(mappedFileURIM1, results[2].Uri); - Assert.True(results[2].Diagnostics.IsEmpty()); - - Assert.Equal(mappedFileURIM2, results[3].Uri); - Assert.Equal("id2", results[3].Diagnostics.Single().Code); - - Assert.Single(testAccessor.GetFileUrisForDocument(document.Id), mappedFileURIM2); - Assert.Equal("id2", testAccessor.GetDiagnosticsForUriAndDocument(document.Id, mappedFileURIM2).Single().Code); - Assert.Empty(testAccessor.GetDiagnosticsForUriAndDocument(document.Id, mappedFileURIM1)); - } - - [Fact] - public async Task RemoveDiagnosticForMappedFileToManyDocumentsTestAsync() - { - using var server = await CreateTestLspServerAsync(new string[] { "", "" }); - var workspace = server.TestWorkspace; - var documents = workspace.CurrentSolution.Projects.First().Documents.ToImmutableArray(); - - var diagnosticsMock = new Mock(MockBehavior.Strict); - // Create diagnostic for the first document that has a mapped location. - var mappedFilePath = documents[0].FilePath + "m1"; - var documentOneDiagnostic = await CreateMockDiagnosticDatasWithMappedLocationAsync(documents[0], ("doc1Diagnostic", mappedFilePath)).ConfigureAwait(false); - // Create diagnostic for the second document that maps to the same location as the first document diagnostic. - var documentTwoDiagnostic = await CreateMockDiagnosticDatasWithMappedLocationAsync(documents[1], ("doc2Diagnostic", mappedFilePath)).ConfigureAwait(false); - - // On the first call for this document, return the mapped diagnostic. On the second, return nothing. - SetupMockDiagnosticSequence(diagnosticsMock, documents[0].Id, documentOneDiagnostic, ImmutableArray.Empty); - // Always return the mapped diagnostic for this document. - SetupMockWithDiagnostics(diagnosticsMock, documents[1].Id, documentTwoDiagnostic); - - // Publish three document change diagnostic notifications -> - // 1. doc1 with doc1Diagnostic = mapped file path m1 - // 2. doc2 with doc2Diagnostic = mapped file path m1 - // 3. doc1 with empty. - // - // We expect three publish diagnostics -> - // 1. from m1 with doc1Diagnostic (triggered by 1 above to add doc1Diagnostic). - // 2. from m1 with doc1Diagnostic and doc2Diagnostic (triggered by 2 above to add doc2Diagnostic). - // 3. from m1 with just doc2Diagnostic (triggered by 3 above to remove doc1Diagnostic). - var (testAccessor, results) = await RunPublishDiagnosticsAsync(workspace, diagnosticsMock.Object, 3, documents[0], documents[1], documents[0]).ConfigureAwait(false); - - Assert.Equal(3, results.Count); - var expectedUri = new Uri(mappedFilePath); - Assert.Equal(expectedUri, results[0].Uri); - Assert.Equal("doc1Diagnostic", results[0].Diagnostics.Single().Code); - - Assert.Equal(expectedUri, results[1].Uri); - Assert.Equal(2, results[1].Diagnostics.Length); - Assert.Contains(results[1].Diagnostics, d => d.Code == "doc1Diagnostic"); - Assert.Contains(results[1].Diagnostics, d => d.Code == "doc2Diagnostic"); - - Assert.Equal(expectedUri, results[2].Uri); - Assert.Equal(1, results[2].Diagnostics.Length); - Assert.Contains(results[2].Diagnostics, d => d.Code == "doc2Diagnostic"); - - Assert.Single(testAccessor.GetFileUrisForDocument(documents[1].Id), expectedUri); - Assert.Equal("doc2Diagnostic", testAccessor.GetDiagnosticsForUriAndDocument(documents[1].Id, expectedUri).Single().Code); - Assert.Empty(testAccessor.GetDiagnosticsForUriAndDocument(documents[0].Id, expectedUri)); - } - - [Fact] - public async Task ClearAllDiagnosticsForMappedFilesTestAsync() - { - using var server = await CreateTestLspServerAsync(""); - var workspace = server.TestWorkspace; - var document = workspace.CurrentSolution.Projects.First().Documents.First(); - - var diagnosticsMock = new Mock(MockBehavior.Strict); - var mappedFilePathM1 = document.FilePath + "m1"; - var mappedFilePathM2 = document.FilePath + "m2"; - // Create two mapped diagnostics for the document on first call. - // On the second call, return only empty diagnostics. - SetupMockDiagnosticSequence(diagnosticsMock, document.Id, - await CreateMockDiagnosticDatasWithMappedLocationAsync(document, ("id1", mappedFilePathM1), ("id2", mappedFilePathM2)).ConfigureAwait(false), - ImmutableArray.Empty); - - // Publish two document change diagnostic notifications -> - // 1. doc1 with id1 = mapped file m1 and id2 = mapped file m2. - // 2. doc1 with empty. - // - // We expect four publish diagnostic notifications - the first two are the two mapped files from 1. - // The second two are the two mapped files being cleared by 2. - var (testAccessor, results) = await RunPublishDiagnosticsAsync(workspace, diagnosticsMock.Object, 4, document, document).ConfigureAwait(false); - - var mappedFileURIM1 = new Uri(document.FilePath + "m1"); - var mappedFileURIM2 = new Uri(document.FilePath + "m2"); - - Assert.Equal(4, results.Count); - - // Document's first update. - Assert.Equal(mappedFileURIM1, results[0].Uri); - Assert.Equal("id1", results[0].Diagnostics.Single().Code); - - Assert.Equal(mappedFileURIM2, results[1].Uri); - Assert.Equal("id2", results[1].Diagnostics.Single().Code); - - // Document's second update. - Assert.Equal(mappedFileURIM1, results[2].Uri); - Assert.True(results[2].Diagnostics.IsEmpty()); - - Assert.Equal(mappedFileURIM2, results[3].Uri); - Assert.True(results[3].Diagnostics.IsEmpty()); - - Assert.Empty(testAccessor.GetDocumentIdsInPublishedUris()); - Assert.Empty(testAccessor.GetFileUrisInPublishDiagnostics()); - } - - [Fact] - public async Task ClearAllDiagnosticsForMappedFileToManyDocumentsTestAsync() - { - using var server = await CreateTestLspServerAsync(new string[] { "", "" }); - var workspace = server.TestWorkspace; - var documents = workspace.CurrentSolution.Projects.First().Documents.ToImmutableArray(); - - var diagnosticsMock = new Mock(MockBehavior.Strict); - // Create diagnostic for the first document that has a mapped location. - var mappedFilePath = documents[0].FilePath + "m1"; - var documentOneDiagnostic = await CreateMockDiagnosticDatasWithMappedLocationAsync(documents[0], ("doc1Diagnostic", mappedFilePath)).ConfigureAwait(false); - // Create diagnostic for the second document that maps to the same location as the first document diagnostic. - var documentTwoDiagnostic = await CreateMockDiagnosticDatasWithMappedLocationAsync(documents[1], ("doc2Diagnostic", mappedFilePath)).ConfigureAwait(false); - - // On the first call for the documents, return the mapped diagnostic. On the second, return nothing. - SetupMockDiagnosticSequence(diagnosticsMock, documents[0].Id, documentOneDiagnostic, ImmutableArray.Empty); - SetupMockDiagnosticSequence(diagnosticsMock, documents[1].Id, documentTwoDiagnostic, ImmutableArray.Empty); - - // Publish four document change diagnostic notifications -> - // 1. doc1 with doc1Diagnostic = mapped file m1. - // 2. doc2 with doc2Diagnostic = mapped file m1. - // 3. doc1 with empty diagnostics. - // 4. doc2 with empty diagnostics. - // - // We expect four publish diagnostics -> - // 1. from URI m1 with doc1Diagnostic (triggered by 1 above to add doc1Diagnostic). - // 2. from URI m1 with doc1Diagnostic and doc2Diagnostic (triggered by 2 above to add doc2Diagnostic). - // 3. from URI m1 with just doc2Diagnostic (triggered by 3 above to clear doc1 diagnostic). - // 4. from URI m1 with empty (triggered by 4 above to also clear doc2 diagnostic). - var (testAccessor, results) = await RunPublishDiagnosticsAsync(workspace, diagnosticsMock.Object, 4, documents[0], documents[1], documents[0], documents[1]).ConfigureAwait(false); - - Assert.Equal(4, results.Count); - var expectedUri = new Uri(mappedFilePath); - Assert.Equal(expectedUri, results[0].Uri); - Assert.Equal("doc1Diagnostic", results[0].Diagnostics.Single().Code); - - Assert.Equal(expectedUri, results[1].Uri); - Assert.Equal(2, results[1].Diagnostics.Length); - Assert.Contains(results[1].Diagnostics, d => d.Code == "doc1Diagnostic"); - Assert.Contains(results[1].Diagnostics, d => d.Code == "doc2Diagnostic"); - - Assert.Equal(expectedUri, results[2].Uri); - Assert.Equal(1, results[2].Diagnostics.Length); - Assert.Contains(results[2].Diagnostics, d => d.Code == "doc2Diagnostic"); - - Assert.Equal(expectedUri, results[3].Uri); - Assert.True(results[3].Diagnostics.IsEmpty()); - - Assert.Empty(testAccessor.GetDocumentIdsInPublishedUris()); - Assert.Empty(testAccessor.GetFileUrisInPublishDiagnostics()); - } - - private async Task<(VisualStudioInProcLanguageServer.TestAccessor, List)> RunPublishDiagnosticsAsync( - TestWorkspace workspace, - IDiagnosticService diagnosticService, - int expectedNumberOfCallbacks, - params Document[] documentsToPublish) - { - var (clientStream, serverStream) = FullDuplexStream.CreatePair(); - var languageServer = CreateLanguageServer(serverStream, serverStream, workspace, diagnosticService); - - // Notification target for tests to receive the notification details - var callback = new Callback(expectedNumberOfCallbacks); - using var jsonRpc = new JsonRpc(clientStream, clientStream, callback) - { - ExceptionStrategy = ExceptionProcessing.ISerializable, - }; - - // The json rpc messages won't necessarily come back in order by default. - // So use a synchronization context to preserve the original ordering. - // https://github.com/microsoft/vs-streamjsonrpc/blob/bc970c61b90db5db135a1b3d1c72ef355c2112af/doc/resiliency.md#when-message-order-is-important - jsonRpc.SynchronizationContext = new RpcOrderPreservingSynchronizationContext(); - jsonRpc.StartListening(); - - // Triggers language server to send notifications. - await languageServer.ProcessDiagnosticUpdatedBatchAsync( - diagnosticService, documentsToPublish.SelectAsArray(d => d.Id), CancellationToken.None); - - // Waits for all notifications to be received. - await callback.CallbackCompletedTask.ConfigureAwait(false); - - return (languageServer.GetTestAccessor(), callback.Results); - - static VisualStudioInProcLanguageServer CreateLanguageServer(Stream inputStream, Stream outputStream, TestWorkspace workspace, IDiagnosticService mockDiagnosticService) - { - var dispatcherFactory = workspace.ExportProvider.GetExportedValue(); - var listenerProvider = workspace.ExportProvider.GetExportedValue(); - var lspWorkspaceRegistrationService = workspace.ExportProvider.GetExportedValue(); - var capabilitiesProvider = workspace.ExportProvider.GetExportedValue(); - - var jsonRpc = new JsonRpc(new HeaderDelimitedMessageHandler(outputStream, inputStream)) - { - ExceptionStrategy = ExceptionProcessing.ISerializable, - }; - - var globalOptions = workspace.GetService(); - - var languageServer = new VisualStudioInProcLanguageServer( - dispatcherFactory, - jsonRpc, - capabilitiesProvider, - lspWorkspaceRegistrationService, - globalOptions, - listenerProvider, - NoOpLspLogger.Instance, - mockDiagnosticService, - ProtocolConstants.RoslynLspLanguages, - clientName: null, - userVisibleServerName: string.Empty, - telemetryServerTypeName: "TestPushDiagnosticsServer"); - - jsonRpc.StartListening(); - return languageServer; - } - } - - private void SetupMockWithDiagnostics(Mock diagnosticServiceMock, DocumentId documentId, ImmutableArray diagnostics) - { - diagnosticServiceMock.Setup(d => d.GetPushDiagnosticsAsync( - It.IsAny(), - It.IsAny(), - documentId, - It.IsAny(), - It.IsAny(), - It.IsAny>(), - It.IsAny())).Returns(new ValueTask>(diagnostics)); - } - - private void SetupMockDiagnosticSequence(Mock diagnosticServiceMock, DocumentId documentId, - ImmutableArray firstDiagnostics, ImmutableArray secondDiagnostics) - { - diagnosticServiceMock.SetupSequence(d => d.GetPushDiagnosticsAsync( - It.IsAny(), - It.IsAny(), - documentId, - It.IsAny(), - It.IsAny(), - It.IsAny>(), - It.IsAny())) - .Returns(new ValueTask>(firstDiagnostics)) - .Returns(new ValueTask>(secondDiagnostics)); - } - - private async Task> CreateMockDiagnosticDataAsync(Document document, string id) - { - var descriptor = new DiagnosticDescriptor(id, "", "", "", DiagnosticSeverity.Error, true); - var location = Location.Create(await document.GetRequiredSyntaxTreeAsync(CancellationToken.None).ConfigureAwait(false), new TextSpan()); - return ImmutableArray.Create(DiagnosticData.Create(Diagnostic.Create(descriptor, location), document)); - } - - private async Task> CreateMockDiagnosticDatasWithMappedLocationAsync(Document document, params (string diagnosticId, string mappedFilePath)[] diagnostics) - { - var tree = await document.GetRequiredSyntaxTreeAsync(CancellationToken.None).ConfigureAwait(false); - - return diagnostics.Select(d => CreateMockDiagnosticDataWithMappedLocation(document, tree, d.diagnosticId, d.mappedFilePath)).ToImmutableArray(); - - static DiagnosticData CreateMockDiagnosticDataWithMappedLocation(Document document, SyntaxTree tree, string id, string mappedFilePath) - { - var descriptor = new DiagnosticDescriptor(id, "", "", "", DiagnosticSeverity.Error, true); - var location = Location.Create(tree, new TextSpan()); - - var diagnostic = Diagnostic.Create(descriptor, location); - return new DiagnosticData(diagnostic.Id, - diagnostic.Descriptor.Category, - null, - null, - diagnostic.Severity, - diagnostic.DefaultSeverity, - diagnostic.Descriptor.IsEnabledByDefault, - diagnostic.WarningLevel, - diagnostic.Descriptor.ImmutableCustomTags(), - diagnostic.Properties, - document.Project.Id, - GetDataLocation(document, mappedFilePath), - additionalLocations: default, - document.Project.Language, - diagnostic.Descriptor.Title.ToString(), - diagnostic.Descriptor.Description.ToString(), - null, - diagnostic.IsSuppressed); - } - - static DiagnosticDataLocation GetDataLocation(Document document, string mappedFilePath) - => new DiagnosticDataLocation(document.Id, originalFilePath: document.FilePath, mappedFilePath: mappedFilePath); - } - - /// - /// Synchronization context to preserve ordering of the RPC messages - /// Adapted from https://dev.azure.com/devdiv/DevDiv/VS%20Cloud%20Kernel/_git/DevCore?path=%2Fsrc%2Fclr%2FMicrosoft.ServiceHub.Framework%2FServiceRpcDescriptor%2BRpcOrderPreservingSynchronizationContext.cs - /// https://github.com/microsoft/vs-streamjsonrpc/issues/440 tracks exposing functionality so we don't need to copy this. - /// - private class RpcOrderPreservingSynchronizationContext : SynchronizationContext, IDisposable - { - /// - /// The queue of work to execute. - /// - private readonly AsyncQueue<(SendOrPostCallback, object?)> _queue = new AsyncQueue<(SendOrPostCallback, object?)>(); - - public RpcOrderPreservingSynchronizationContext() - { - // Process the work in the background. - this.ProcessQueueAsync().Forget(); - } - - public override void Post(SendOrPostCallback d, object? state) => this._queue.Enqueue((d, state)); - - public override void Send(SendOrPostCallback d, object? state) => throw new NotSupportedException(); - - public override SynchronizationContext CreateCopy() => throw new NotSupportedException(); - - /// - /// Causes this to reject all future posted work and - /// releases the queue processor when it is empty. - /// - public void Dispose() => this._queue.Complete(); - - /// - /// Executes queued work on the thread-pool, one at a time. - /// Don't catch exceptions - let them bubble up to fail the test. - /// - private async Task ProcessQueueAsync() - { - while (!this._queue.IsCompleted) - { - var work = await this._queue.DequeueAsync().ConfigureAwait(false); - work.Item1(work.Item2); - } - } - } - - private class Callback - { - private readonly TaskCompletionSource _callbackCompletedTaskSource = new(); - /// - /// Task that can be awaited for the all callbacks to complete. - /// - public Task CallbackCompletedTask => _callbackCompletedTaskSource.Task; - - /// - /// Serialized results of all publish diagnostic notifications received by this callback. - /// - public List Results { get; } - - /// - /// Lock to guard concurrent callbacks. - /// - private readonly object _lock = new(); - - /// - /// The expected number of times this callback should be hit. - /// Used in conjunction with - /// to determine if the callbacks are complete. - /// - private readonly int _expectedNumberOfCallbacks; - - /// - /// The current number of callbacks that this callback has been hit. - /// - private int _currentNumberOfCallbacks; - - public Callback(int expectedNumberOfCallbacks) - { - Results = new List(); - _expectedNumberOfCallbacks = expectedNumberOfCallbacks; - _currentNumberOfCallbacks = 0; - - if (expectedNumberOfCallbacks == 0) - _callbackCompletedTaskSource.SetResult(null); - } - - [JsonRpcMethod(LSP.Methods.TextDocumentPublishDiagnosticsName)] - public Task OnDiagnosticsPublished(JToken input) - { - lock (_lock) - { - _currentNumberOfCallbacks++; - Contract.ThrowIfTrue(_currentNumberOfCallbacks > _expectedNumberOfCallbacks, "received too many callbacks"); - - var diagnosticParams = input.ToObject(); - Assumes.Present(diagnosticParams); - - Results.Add(diagnosticParams); - - if (_currentNumberOfCallbacks == _expectedNumberOfCallbacks) - _callbackCompletedTaskSource.SetResult(null); - - return Task.CompletedTask; - } - } - } - - private class TestLanguageClient : AbstractInProcLanguageClient - { - public TestLanguageClient() - : base(null!, null!, null, null!, null!, null!, null!, null) - { - } - - protected override ImmutableArray SupportedLanguages => ProtocolConstants.RoslynLspLanguages; - - public override string Name => nameof(LspDiagnosticsTests); - - public override bool ShowNotificationOnInitializeFailed => false; - - public override LSP.ServerCapabilities GetCapabilities(LSP.ClientCapabilities clientCapabilities) => new(); - } - } -} diff --git a/src/VisualStudio/Core/Test.Next/Services/PerformanceTrackerServiceTests.cs b/src/VisualStudio/Core/Test.Next/Services/PerformanceTrackerServiceTests.cs index e7a06d5333c38..60b7e8b8d3d24 100644 --- a/src/VisualStudio/Core/Test.Next/Services/PerformanceTrackerServiceTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/PerformanceTrackerServiceTests.cs @@ -70,7 +70,7 @@ public void TestBadAnalyzerInfoPII() Assert.True(badAnalyzer2.PIISafeAnalyzerId == "test".GetHashCode().ToString()); } - private void VerifyBadAnalyzer(ExpensiveAnalyzerInfo analyzer, string analyzerId, double lof, double mean, double stddev) + private static void VerifyBadAnalyzer(ExpensiveAnalyzerInfo analyzer, string analyzerId, double lof, double mean, double stddev) { Assert.True(analyzer.PIISafeAnalyzerId.IndexOf(analyzerId, StringComparison.OrdinalIgnoreCase) >= 0); Assert.Equal(lof, analyzer.LocalOutlierFactor, precision: 4); @@ -78,7 +78,7 @@ private void VerifyBadAnalyzer(ExpensiveAnalyzerInfo analyzer, string analyzerId Assert.Equal(stddev, analyzer.AdjustedStandardDeviation, precision: 4); } - private List GetBadAnalyzers(string testFileName, int to) + private static List GetBadAnalyzers(string testFileName, int to) { var testFile = ReadTestFile(testFileName); @@ -99,7 +99,7 @@ private List GetBadAnalyzers(string testFileName, int to) return badAnalyzerInfo; } - private IEnumerable CreateSnapshots(Dictionary matrix, int index) + private static IEnumerable CreateSnapshots(Dictionary matrix, int index) { foreach (var kv in matrix) { @@ -113,7 +113,7 @@ private IEnumerable CreateSnapshots(Dictionary matrix, int dataCount) CreateMatrix(string testFile) + private static (Dictionary matrix, int dataCount) CreateMatrix(string testFile) { var matrix = new Dictionary(); @@ -151,23 +151,23 @@ private IEnumerable CreateSnapshots(Dictionary(recoveredSolution.Workspace); var primaryWorkspace = recoveredSolution.Workspace; Assert.Equal(solutionChecksum, await recoveredSolution.State.GetChecksumAsync(CancellationToken.None)); + Assert.Same(primaryWorkspace.PrimaryBranchId, recoveredSolution.BranchId); // get new solution var newSolution = newSolutionGetter(solution); @@ -806,12 +807,14 @@ private static async Task VerifySolutionUpdate( var recoveredNewSolution = await remoteWorkspace.GetSolutionAsync(assetProvider, newSolutionChecksum, fromPrimaryBranch: false, workspaceVersion: -1, projectId: null, CancellationToken.None); Assert.Equal(newSolutionChecksum, await recoveredNewSolution.State.GetChecksumAsync(CancellationToken.None)); + Assert.NotSame(primaryWorkspace.PrimaryBranchId, recoveredNewSolution.BranchId); // do same once updating primary workspace await remoteWorkspace.UpdatePrimaryBranchSolutionAsync(assetProvider, newSolutionChecksum, solution.WorkspaceVersion + 1, CancellationToken.None); var third = await remoteWorkspace.GetSolutionAsync(assetProvider, newSolutionChecksum, fromPrimaryBranch: false, workspaceVersion: -1, projectId: null, CancellationToken.None); Assert.Equal(newSolutionChecksum, await third.State.GetChecksumAsync(CancellationToken.None)); + Assert.Same(primaryWorkspace.PrimaryBranchId, third.BranchId); newSolutionValidator?.Invoke(recoveredNewSolution); } diff --git a/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs b/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs index adcdafa8f3e5e..ae55dec64f47b 100644 --- a/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs @@ -237,7 +237,7 @@ private static async Task AnalyzeAsync(TestWorkspace w return result.AnalysisResult[analyzerDriver.Analyzers[0]]; } - private TestWorkspace CreateWorkspace(string language, string code, ParseOptions options = null) + private static TestWorkspace CreateWorkspace(string language, string code, ParseOptions options = null) { var composition = EditorTestCompositions.EditorFeatures.WithTestHostParts(TestHost.OutOfProcess); diff --git a/src/VisualStudio/Core/Test/AnalyzerSupport/AnalyzerDependencyCheckerTests.vb b/src/VisualStudio/Core/Test/AnalyzerSupport/AnalyzerDependencyCheckerTests.vb index 028d4d170448c..7403554b7e583 100644 --- a/src/VisualStudio/Core/Test/AnalyzerSupport/AnalyzerDependencyCheckerTests.vb +++ b/src/VisualStudio/Core/Test/AnalyzerSupport/AnalyzerDependencyCheckerTests.vb @@ -861,7 +861,7 @@ public class A Assert.False(ignorableAssemblyList.Includes(alpha)) End Sub - Private Function BuildLibrary(directory As DisposableDirectory, fileContents As String, libraryName As String, ParamArray referenceNames As String()) As String + Private Shared Function BuildLibrary(directory As DisposableDirectory, fileContents As String, libraryName As String, ParamArray referenceNames As String()) As String Dim sourceFile = directory.CreateFile(libraryName + ".cs").WriteAllText(fileContents).Path Dim tempOut = Path.Combine(directory.Path, libraryName + ".out") Dim libraryOut = Path.Combine(directory.Path, libraryName + ".dll") diff --git a/src/VisualStudio/Core/Test/ChangeSignature/AddParameterViewModelTests.vb b/src/VisualStudio/Core/Test/ChangeSignature/AddParameterViewModelTests.vb index 83abc819f229c..a2ed94dbb955b 100644 --- a/src/VisualStudio/Core/Test/ChangeSignature/AddParameterViewModelTests.vb +++ b/src/VisualStudio/Core/Test/ChangeSignature/AddParameterViewModelTests.vb @@ -253,7 +253,7 @@ class MyClass Assert.True(viewModel.TrySubmit()) End Sub - Private Sub AssertTypeBindingIconAndTextIs(viewModel As AddParameterDialogViewModel, currentIcon As String, expectedMessage As String) + Private Shared Sub AssertTypeBindingIconAndTextIs(viewModel As AddParameterDialogViewModel, currentIcon As String, expectedMessage As String) Assert.True(viewModel.TypeIsEmptyImage = If(NameOf(viewModel.TypeIsEmptyImage) = currentIcon, Visibility.Visible, Visibility.Collapsed)) Assert.True(viewModel.TypeDoesNotParseImage = If(NameOf(viewModel.TypeDoesNotParseImage) = currentIcon, Visibility.Visible, Visibility.Collapsed)) Assert.True(viewModel.TypeDoesNotBindImage = If(NameOf(viewModel.TypeDoesNotBindImage) = currentIcon, Visibility.Visible, Visibility.Collapsed)) @@ -262,7 +262,7 @@ class MyClass Assert.Equal(expectedMessage, viewModel.TypeBindsDynamicStatus) End Sub - Private Sub VerifyOpeningState(viewModel As AddParameterDialogViewModel) + Private Shared Sub VerifyOpeningState(viewModel As AddParameterDialogViewModel) Assert.True(viewModel.TypeBindsDynamicStatus = ServicesVSResources.Please_enter_a_type_name) Assert.True(viewModel.TypeIsEmptyImage = Visibility.Visible) @@ -285,7 +285,7 @@ class MyClass Assert.Equal(ServicesVSResources.A_type_and_name_must_be_provided, message) End Sub - Private Function GetViewModelTestStateAsync( + Private Shared Function GetViewModelTestStateAsync( markup As XElement, languageName As String) As AddParameterViewModelTestState diff --git a/src/VisualStudio/Core/Test/ChangeSignature/ChangeSignatureViewModelTests.vb b/src/VisualStudio/Core/Test/ChangeSignature/ChangeSignatureViewModelTests.vb index 5224cf91c24bb..50a0b60132c7c 100644 --- a/src/VisualStudio/Core/Test/ChangeSignature/ChangeSignatureViewModelTests.vb +++ b/src/VisualStudio/Core/Test/ChangeSignature/ChangeSignatureViewModelTests.vb @@ -341,7 +341,7 @@ class Goo defaultValue:="default") End Function - Private Sub VerifyAlteredState( + Private Shared Sub VerifyAlteredState( viewModelTestState As ChangeSignatureViewModelTestState, Optional monitor As PropertyChangedTestMonitor = Nothing, Optional canCommit As Boolean? = Nothing, @@ -393,7 +393,7 @@ class Goo End Sub - Private Sub AssertPermuted(permutation As Integer(), actualParameterList As List(Of ChangeSignatureDialogViewModel.ParameterViewModel), originalParameterList As ImmutableArray(Of IParameterSymbol)) + Private Shared Sub AssertPermuted(permutation As Integer(), actualParameterList As List(Of ChangeSignatureDialogViewModel.ParameterViewModel), originalParameterList As ImmutableArray(Of IParameterSymbol)) Dim finalParameterList = actualParameterList.Where(Function(p) Not p.IsRemoved) For index = 0 To permutation.Length - 1 Dim expected = originalParameterList(permutation(index)) @@ -401,7 +401,7 @@ class Goo Next End Sub - Private Sub VerifyOpeningState(viewModel As ChangeSignatureDialogViewModel, openingSignatureDisplay As String) + Private Shared Sub VerifyOpeningState(viewModel As ChangeSignatureDialogViewModel, openingSignatureDisplay As String) Assert.Equal(openingSignatureDisplay, viewModel.TEST_GetSignatureDisplayText()) Dim message As String = Nothing Assert.False(viewModel.CanSubmit(message)) @@ -409,7 +409,7 @@ class Goo Assert.False(viewModel.CanMoveUp) End Sub - Private Sub VerifyParameterInfo( + Private Shared Sub VerifyParameterInfo( viewModel As ChangeSignatureDialogViewModel, parameterIndex As Integer, Optional modifier As String = Nothing, @@ -446,7 +446,7 @@ class Goo End If End Sub - Private Async Function GetViewModelTestStateAsync( + Private Shared Async Function GetViewModelTestStateAsync( markup As XElement, languageName As String) As Tasks.Task(Of ChangeSignatureViewModelTestState) diff --git a/src/VisualStudio/Core/Test/ClassView/SyncClassViewTests.vb b/src/VisualStudio/Core/Test/ClassView/SyncClassViewTests.vb index 5c8726d5e5c45..a856c7da09eb1 100644 --- a/src/VisualStudio/Core/Test/ClassView/SyncClassViewTests.vb +++ b/src/VisualStudio/Core/Test/ClassView/SyncClassViewTests.vb @@ -860,7 +860,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ClassView #End Region - Private Sub Test( + Private Shared Sub Test( workspaceDefinition As XElement, ParamArray presentationNodes As NodeVerifier() ) diff --git a/src/VisualStudio/Core/Test/CodeModel/AbstractCodeElementTests`1.vb b/src/VisualStudio/Core/Test/CodeModel/AbstractCodeElementTests`1.vb index 0818098843da2..3b513002dec61 100644 --- a/src/VisualStudio/Core/Test/CodeModel/AbstractCodeElementTests`1.vb +++ b/src/VisualStudio/Core/Test/CodeModel/AbstractCodeElementTests`1.vb @@ -1109,13 +1109,13 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.CodeModel End Sub) End Sub - Private Sub TestAllParameterNamesByName(parameters As EnvDTE.CodeElements, expectedParameterNames() As String) + Private Shared Sub TestAllParameterNamesByName(parameters As EnvDTE.CodeElements, expectedParameterNames() As String) For index = 0 To expectedParameterNames.Count() - 1 Assert.NotNull(parameters.Item(expectedParameterNames(index))) Next End Sub - Private Sub TestAllParameterNamesByIndex(parameters As EnvDTE.CodeElements, expectedParameterNames() As String) + Private Shared Sub TestAllParameterNamesByIndex(parameters As EnvDTE.CodeElements, expectedParameterNames() As String) For index = 0 To expectedParameterNames.Count() - 1 ' index + 1 for Item because Parameters are not zero indexed Assert.Equal(expectedParameterNames(index), parameters.Item(index + 1).Name) diff --git a/src/VisualStudio/Core/Test/CodeModel/AbstractEventCollectorTests.vb b/src/VisualStudio/Core/Test/CodeModel/AbstractEventCollectorTests.vb index 3671be8ece2eb..e5a05c7353160 100644 --- a/src/VisualStudio/Core/Test/CodeModel/AbstractEventCollectorTests.vb +++ b/src/VisualStudio/Core/Test/CodeModel/AbstractEventCollectorTests.vb @@ -75,7 +75,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.CodeModel End Sub End Function - Private Sub CheckCodeModelEvents(codeModelEvent As CodeModelEvent, codeModelService As ICodeModelService, node As String, parent As String) + Private Shared Sub CheckCodeModelEvents(codeModelEvent As CodeModelEvent, codeModelService As ICodeModelService, node As String, parent As String) If node IsNot Nothing Then Assert.NotNull(codeModelEvent.Node) Assert.Equal(node, codeModelService.GetName(codeModelEvent.Node)) diff --git a/src/VisualStudio/Core/Test/CodeModel/CSharp/CodeFunctionTests.vb b/src/VisualStudio/Core/Test/CodeModel/CSharp/CodeFunctionTests.vb index 9c2af15a01723..2071deb26408a 100644 --- a/src/VisualStudio/Core/Test/CodeModel/CSharp/CodeFunctionTests.vb +++ b/src/VisualStudio/Core/Test/CodeModel/CSharp/CodeFunctionTests.vb @@ -2677,11 +2677,11 @@ class C TestPropertyDescriptors(Of EnvDTE80.CodeFunction2)(code) End Sub - Private Function GetExtensionMethodExtender(codeElement As EnvDTE80.CodeFunction2) As ICSExtensionMethodExtender + Private Shared Function GetExtensionMethodExtender(codeElement As EnvDTE80.CodeFunction2) As ICSExtensionMethodExtender Return CType(codeElement.Extender(ExtenderNames.ExtensionMethod), ICSExtensionMethodExtender) End Function - Private Function GetPartialMethodExtender(codeElement As EnvDTE80.CodeFunction2) As ICSPartialMethodExtender + Private Shared Function GetPartialMethodExtender(codeElement As EnvDTE80.CodeFunction2) As ICSPartialMethodExtender Return CType(codeElement.Extender(ExtenderNames.PartialMethod), ICSPartialMethodExtender) End Function diff --git a/src/VisualStudio/Core/Test/CodeModel/CSharp/CodePropertyTests.vb b/src/VisualStudio/Core/Test/CodeModel/CSharp/CodePropertyTests.vb index 38c13f9aa1aad..b49059ddf835d 100644 --- a/src/VisualStudio/Core/Test/CodeModel/CSharp/CodePropertyTests.vb +++ b/src/VisualStudio/Core/Test/CodeModel/CSharp/CodePropertyTests.vb @@ -1680,7 +1680,7 @@ class C TestPropertyDescriptors(Of EnvDTE80.CodeProperty2)(code) End Sub - Private Function GetAutoImplementedPropertyExtender(codeElement As EnvDTE80.CodeProperty2) As ICSAutoImplementedPropertyExtender + Private Shared Function GetAutoImplementedPropertyExtender(codeElement As EnvDTE80.CodeProperty2) As ICSAutoImplementedPropertyExtender Return CType(codeElement.Extender(ExtenderNames.AutoImplementedProperty), ICSAutoImplementedPropertyExtender) End Function diff --git a/src/VisualStudio/Core/Test/CodeModel/CSharp/SyntaxNodeKeyTests.vb b/src/VisualStudio/Core/Test/CodeModel/CSharp/SyntaxNodeKeyTests.vb index 1f3ef6afad584..92899ccb36941 100644 --- a/src/VisualStudio/Core/Test/CodeModel/CSharp/SyntaxNodeKeyTests.vb +++ b/src/VisualStudio/Core/Test/CodeModel/CSharp/SyntaxNodeKeyTests.vb @@ -226,7 +226,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.CodeModel.CSharp Await TestAsync(input, "C.#op_Implicit_int(C)", 1) End Function - Private Async Function TestAsync(definition As XElement, expectedName As String, expectedOrdinal As Integer) As Task + Private Shared Async Function TestAsync(definition As XElement, expectedName As String, expectedOrdinal As Integer) As Task Using workspace = TestWorkspace.Create(definition, composition:=VisualStudioTestCompositions.LanguageServices) Dim project = workspace.CurrentSolution.Projects.First() Dim codeModelService = project.LanguageServices.GetService(Of ICodeModelService)() diff --git a/src/VisualStudio/Core/Test/CodeModel/MethodXML/MethodXMLTests.vb b/src/VisualStudio/Core/Test/CodeModel/MethodXML/MethodXMLTests.vb index d769642fd90d5..82f31646e6578 100644 --- a/src/VisualStudio/Core/Test/CodeModel/MethodXML/MethodXMLTests.vb +++ b/src/VisualStudio/Core/Test/CodeModel/MethodXML/MethodXMLTests.vb @@ -9,7 +9,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.CodeModel.MethodXML <[UseExportProvider]> Partial Public Class MethodXMLTests - Private Sub Test(definition As XElement, expected As XElement) + Private Shared Sub Test(definition As XElement, expected As XElement) Using state = CreateCodeModelTestState(definition) Dim func = state.GetCodeElementAtCursor(Of EnvDTE.CodeFunction)() Dim actual = func.GetMethodXML() diff --git a/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeClassTests.vb b/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeClassTests.vb index 18a5933e2d654..035f8318ffbe4 100644 --- a/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeClassTests.vb +++ b/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeClassTests.vb @@ -3261,7 +3261,7 @@ End Class End Sub) End Sub - Private Function GetGenericExtender(codeElement As EnvDTE80.CodeClass2) As IVBGenericExtender + Private Shared Function GetGenericExtender(codeElement As EnvDTE80.CodeClass2) As IVBGenericExtender Return CType(codeElement.Extender(ExtenderNames.VBGenericExtender), IVBGenericExtender) End Function diff --git a/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeDelegateTests.vb b/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeDelegateTests.vb index d09fcc1ba24f2..891fc8d23eb4e 100644 --- a/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeDelegateTests.vb +++ b/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeDelegateTests.vb @@ -591,7 +591,7 @@ Delegate Sub M() #End Region - Private Function GetGenericExtender(codeElement As EnvDTE80.CodeDelegate2) As IVBGenericExtender + Private Shared Function GetGenericExtender(codeElement As EnvDTE80.CodeDelegate2) As IVBGenericExtender Return CType(codeElement.Extender(ExtenderNames.VBGenericExtender), IVBGenericExtender) End Function diff --git a/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeEnumTests.vb b/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeEnumTests.vb index 0452fe7092979..aad0058ae31d7 100644 --- a/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeEnumTests.vb +++ b/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeEnumTests.vb @@ -312,7 +312,7 @@ End Enum #End Region - Private Function GetGenericExtender(codeElement As EnvDTE.CodeEnum) As IVBGenericExtender + Private Shared Function GetGenericExtender(codeElement As EnvDTE.CodeEnum) As IVBGenericExtender Return CType(codeElement.Extender(ExtenderNames.VBGenericExtender), IVBGenericExtender) End Function diff --git a/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeFunctionTests.vb b/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeFunctionTests.vb index 588726ee43a13..52ae763e80c3d 100644 --- a/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeFunctionTests.vb +++ b/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeFunctionTests.vb @@ -2881,7 +2881,7 @@ End Class #End Region - Private Function GetPartialMethodExtender(codeElement As EnvDTE80.CodeFunction2) As IVBPartialMethodExtender + Private Shared Function GetPartialMethodExtender(codeElement As EnvDTE80.CodeFunction2) As IVBPartialMethodExtender Return CType(codeElement.Extender(ExtenderNames.VBPartialMethodExtender), IVBPartialMethodExtender) End Function diff --git a/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeInterfaceTests.vb b/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeInterfaceTests.vb index 83dc395f75125..844ecd8bfb8e3 100644 --- a/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeInterfaceTests.vb +++ b/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeInterfaceTests.vb @@ -430,7 +430,7 @@ End Namespace #End Region - Private Function GetGenericExtender(codeElement As EnvDTE80.CodeInterface2) As IVBGenericExtender + Private Shared Function GetGenericExtender(codeElement As EnvDTE80.CodeInterface2) As IVBGenericExtender Return CType(codeElement.Extender(ExtenderNames.VBGenericExtender), IVBGenericExtender) End Function diff --git a/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodePropertyTests.vb b/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodePropertyTests.vb index 0c219bc7a78c7..badce51192cbd 100644 --- a/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodePropertyTests.vb +++ b/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodePropertyTests.vb @@ -1546,7 +1546,7 @@ End Class #End Region - Private Function GetAutoImplementedPropertyExtender(codeElement As EnvDTE80.CodeProperty2) As IVBAutoPropertyExtender + Private Shared Function GetAutoImplementedPropertyExtender(codeElement As EnvDTE80.CodeProperty2) As IVBAutoPropertyExtender Return CType(codeElement.Extender(ExtenderNames.VBAutoPropertyExtender), IVBAutoPropertyExtender) End Function diff --git a/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeStructTests.vb b/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeStructTests.vb index 76d016a67002a..90403d07548c9 100644 --- a/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeStructTests.vb +++ b/src/VisualStudio/Core/Test/CodeModel/VisualBasic/CodeStructTests.vb @@ -386,7 +386,7 @@ End Namespace #End Region - Private Function GetGenericExtender(codeElement As EnvDTE80.CodeStruct2) As IVBGenericExtender + Private Shared Function GetGenericExtender(codeElement As EnvDTE80.CodeStruct2) As IVBGenericExtender Return CType(codeElement.Extender(ExtenderNames.VBGenericExtender), IVBGenericExtender) End Function diff --git a/src/VisualStudio/Core/Test/CommonControls/MemberSelectionViewModelTests.vb b/src/VisualStudio/Core/Test/CommonControls/MemberSelectionViewModelTests.vb index 453be35d609ec..de0dace83609d 100644 --- a/src/VisualStudio/Core/Test/CommonControls/MemberSelectionViewModelTests.vb +++ b/src/VisualStudio/Core/Test/CommonControls/MemberSelectionViewModelTests.vb @@ -154,7 +154,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.CommonControls Assert.False(FindMemberByName("FooEvent", viewModel.Members).IsChecked) End Function - Private Function FindMemberByName(name As String, memberArray As ImmutableArray(Of PullMemberUpSymbolViewModel)) As PullMemberUpSymbolViewModel + Private Shared Function FindMemberByName(name As String, memberArray As ImmutableArray(Of PullMemberUpSymbolViewModel)) As PullMemberUpSymbolViewModel Dim member = memberArray.FirstOrDefault(Function(memberViewModel) memberViewModel.SymbolName.Equals(name)) If (member Is Nothing) Then Assert.True(False, $"No member called {name} found") @@ -163,7 +163,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.CommonControls Return member End Function - Private Async Function GetViewModelAsync(markup As XElement, languageName As String) As Task(Of MemberSelectionViewModel) + Private Shared Async Function GetViewModelAsync(markup As XElement, languageName As String) As Task(Of MemberSelectionViewModel) Dim workspaceXml = CommonReferences="true"> diff --git a/src/VisualStudio/Core/Test/CommonControls/NewTypeDestinationSelectionViewModelTests.vb b/src/VisualStudio/Core/Test/CommonControls/NewTypeDestinationSelectionViewModelTests.vb index 76f03f38f848c..5ed018391f96e 100644 --- a/src/VisualStudio/Core/Test/CommonControls/NewTypeDestinationSelectionViewModelTests.vb +++ b/src/VisualStudio/Core/Test/CommonControls/NewTypeDestinationSelectionViewModelTests.vb @@ -211,7 +211,7 @@ class $$MyClass monitor.Detach() End Function - Private Async Function GetViewModelAsync(markup As XElement, + Private Shared Async Function GetViewModelAsync(markup As XElement, languageName As String, defaultTypeName As String, Optional defaultNamespace As String = "", diff --git a/src/VisualStudio/Core/Test/Completion/CSharpCompletionSnippetNoteTests.vb b/src/VisualStudio/Core/Test/Completion/CSharpCompletionSnippetNoteTests.vb index 7e3edb97b1851..23458b17b36b6 100644 --- a/src/VisualStudio/Core/Test/Completion/CSharpCompletionSnippetNoteTests.vb +++ b/src/VisualStudio/Core/Test/Completion/CSharpCompletionSnippetNoteTests.vb @@ -129,7 +129,7 @@ class C End Using End Function - Private Function CreateCSharpSnippetExpansionNoteTestState(xElement As XElement, ParamArray snippetShortcuts As String()) As TestState + Private Shared Function CreateCSharpSnippetExpansionNoteTestState(xElement As XElement, ParamArray snippetShortcuts As String()) As TestState Dim state = TestStateFactory.CreateCSharpTestState( xElement, extraExportedTypes:=New List(Of Type) From {GetType(CSharpMockCompletionProvider), GetType(TestCSharpSnippetInfoService)}) diff --git a/src/VisualStudio/Core/Test/Completion/VisualBasicCompletionSnippetNoteTests.vb b/src/VisualStudio/Core/Test/Completion/VisualBasicCompletionSnippetNoteTests.vb index b8e4b438963fe..b70fdc8299152 100644 --- a/src/VisualStudio/Core/Test/Completion/VisualBasicCompletionSnippetNoteTests.vb +++ b/src/VisualStudio/Core/Test/Completion/VisualBasicCompletionSnippetNoteTests.vb @@ -78,7 +78,7 @@ End Class]]> End Using End Function - Private Function CreateVisualBasicSnippetExpansionNoteTestState(xElement As XElement, ParamArray snippetShortcuts As String()) As TestState + Private Shared Function CreateVisualBasicSnippetExpansionNoteTestState(xElement As XElement, ParamArray snippetShortcuts As String()) As TestState Dim state = TestStateFactory.CreateVisualBasicTestState( xElement, New List(Of Type) From {GetType(VisualBasicMockCompletionProvider), GetType(TestVisualBasicSnippetInfoService)}) diff --git a/src/VisualStudio/Core/Test/Diagnostics/DefaultDiagnosticUpdateSourceTests.vb b/src/VisualStudio/Core/Test/Diagnostics/DefaultDiagnosticUpdateSourceTests.vb index 563ecdd2b5a28..63a346d727f29 100644 --- a/src/VisualStudio/Core/Test/Diagnostics/DefaultDiagnosticUpdateSourceTests.vb +++ b/src/VisualStudio/Core/Test/Diagnostics/DefaultDiagnosticUpdateSourceTests.vb @@ -106,7 +106,7 @@ class A Await listenerProvider.GetWaiter(FeatureAttribute.DiagnosticService).ExpeditedWaitAsync() Dim diagnostics = Await diagnosticService.GetPushDiagnosticsAsync( - workspace, document.Project.Id, document.Id, Nothing, includeSuppressedDiagnostics:=False, InternalDiagnosticsOptions.NormalDiagnosticMode, CancellationToken.None) + workspace, document.Project.Id, document.Id, Nothing, includeSuppressedDiagnostics:=False, DiagnosticMode.Default, CancellationToken.None) Assert.Single(diagnostics) End Using @@ -144,7 +144,7 @@ class A Await listenerProvider.GetWaiter(FeatureAttribute.DiagnosticService).ExpeditedWaitAsync() Dim diagnostics = Await diagnosticService.GetPushDiagnosticsAsync( - workspace, document.Project.Id, document.Id, Nothing, includeSuppressedDiagnostics:=False, InternalDiagnosticsOptions.NormalDiagnosticMode, CancellationToken.None) + workspace, document.Project.Id, document.Id, Nothing, includeSuppressedDiagnostics:=False, DiagnosticMode.Default, CancellationToken.None) ' error CS0246: The type or namespace name 'M' could not be found AssertEx.Equal({"CS0246"}, diagnostics.Select(Function(d) d.Id)) @@ -183,7 +183,7 @@ class A Await listenerProvider.GetWaiter(FeatureAttribute.DiagnosticService).ExpeditedWaitAsync() Dim diagnostics = Await diagnosticService.GetPushDiagnosticsAsync( - workspace, document.Project.Id, document.Id, Nothing, includeSuppressedDiagnostics:=False, InternalDiagnosticsOptions.NormalDiagnosticMode, CancellationToken.None) + workspace, document.Project.Id, document.Id, Nothing, includeSuppressedDiagnostics:=False, DiagnosticMode.Default, CancellationToken.None) ' error CS1002: ; expected ' error CS0246: The type or namespace name 'M' could not be found @@ -225,7 +225,7 @@ class A Await listenerProvider.GetWaiter(FeatureAttribute.DiagnosticService).ExpeditedWaitAsync() Dim diagnostics = Await diagnosticService.GetPushDiagnosticsAsync( - workspace, document.Project.Id, document.Id, Nothing, includeSuppressedDiagnostics:=False, InternalDiagnosticsOptions.NormalDiagnosticMode, CancellationToken.None) + workspace, document.Project.Id, document.Id, Nothing, includeSuppressedDiagnostics:=False, DiagnosticMode.Default, CancellationToken.None) AssertEx.Empty(diagnostics) End Using @@ -328,7 +328,7 @@ End Class Await listenerProvider.GetWaiter(FeatureAttribute.DiagnosticService).ExpeditedWaitAsync() Dim diagnostics = Await diagnosticService.GetPushDiagnosticsAsync( - workspace, document.Project.Id, document.Id, Nothing, includeSuppressedDiagnostics:=False, InternalDiagnosticsOptions.NormalDiagnosticMode, CancellationToken.None) + workspace, document.Project.Id, document.Id, Nothing, includeSuppressedDiagnostics:=False, DiagnosticMode.Default, CancellationToken.None) Assert.Single(diagnostics) End Using diff --git a/src/VisualStudio/Core/Test/Diagnostics/DiagnosticTableDataSourceTests.vb b/src/VisualStudio/Core/Test/Diagnostics/DiagnosticTableDataSourceTests.vb index 10fc028f97f36..3d246a4059334 100644 --- a/src/VisualStudio/Core/Test/Diagnostics/DiagnosticTableDataSourceTests.vb +++ b/src/VisualStudio/Core/Test/Diagnostics/DiagnosticTableDataSourceTests.vb @@ -481,53 +481,6 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics End Using End Sub - - Public Sub TestBingHelpLink() - Using workspace = TestWorkspace.CreateVisualBasic(String.Empty) - Dim globalOptions = workspace.GetService(Of IGlobalOptionService)() - Dim documentId = workspace.CurrentSolution.Projects.First().DocumentIds.First() - Dim projectId = documentId.ProjectId - - Dim item1 = CreateItem(projectId, documentId, DiagnosticSeverity.Error) - Dim provider = New TestDiagnosticService(item1) - - Dim tableManagerProvider = New TestTableManagerProvider() - - Dim table = VisualStudioDiagnosticListTableWorkspaceEventListener.VisualStudioDiagnosticListTable.TestAccessor.Create(workspace, globalOptions, provider, tableManagerProvider) - provider.RaiseDiagnosticsUpdated(workspace) - - Dim manager = DirectCast(table.TableManager, TestTableManagerProvider.TestTableManager) - Dim source = DirectCast(manager.Sources.First(), AbstractRoslynTableDataSource(Of DiagnosticTableItem, DiagnosticsUpdatedArgs)) - Dim sinkAndSubscription = manager.Sinks_TestOnly.First() - - Dim sink = DirectCast(sinkAndSubscription.Key, TestTableManagerProvider.TestTableManager.TestSink) - Dim snapshot = sink.Entries.First().GetCurrentSnapshot() - Assert.Equal(1, snapshot.Count) - - Dim helpLink As Object = Nothing - Assert.True(snapshot.TryGetValue(0, StandardTableKeyNames.HelpLink, helpLink)) - - Assert.Equal($"https://bingdev.cloudapp.net/BingUrl.svc/Get?selectedText=test%20format&mainLanguage=Visual%20Basic&requestId={BrowserHelper.EscapedRequestId}&errorCode=test", helpLink.ToString()) - End Using - End Sub - - - Public Async Function TestBingHelpLink_NoCustomType() As Task - Using workspace = TestWorkspace.CreateCSharp("class A { int 111a; }") - Dim diagnostic = (Await workspace.CurrentSolution.Projects.First().GetCompilationAsync()).GetDiagnostics().First(Function(d) d.Id = "CS1519") - - Dim helpMessage = diagnostic.GetBingHelpMessage(workspace.Options) - Assert.Equal("Invalid token '111' in class, record, struct, or interface member declaration", helpMessage) - - ' turn off custom type search - Dim optionServices = workspace.Services.GetService(Of IOptionService)() - optionServices.SetOptions(optionServices.GetOptions().WithChangedOption(InternalDiagnosticsOptions.PutCustomTypeInBingSearch, False)) - - Dim helpMessage2 = diagnostic.GetBingHelpMessage(optionServices.GetOptions()) - Assert.Equal("Invalid token '{0}' in class, record, struct, or interface member declaration", helpMessage2) - End Using - End Function - Public Sub TestErrorSource() Using workspace = TestWorkspace.CreateCSharp(String.Empty) @@ -709,7 +662,6 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics diagnostic1.Id, diagnostic1.Category, diagnostic1.Message, - diagnostic1.ENUMessageForBingSearch, diagnostic1.Severity, diagnostic1.DefaultSeverity, diagnostic1.IsEnabledByDefault, @@ -743,7 +695,6 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics diagnostic2.Id, diagnostic2.Category, diagnostic2.Message, - diagnostic2.ENUMessageForBingSearch, diagnostic2.Severity, diagnostic2.Severity, diagnostic2.IsEnabledByDefault, @@ -793,7 +744,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics End Using End Function - Private Sub RunCompilerAnalyzer(workspace As TestWorkspace) + Private Shared Sub RunCompilerAnalyzer(workspace As TestWorkspace) Dim snapshot = workspace.CurrentSolution Dim analyzerService = Assert.IsType(Of DiagnosticAnalyzerService)(workspace.ExportProvider.GetExportedValue(Of IDiagnosticAnalyzerService)()) @@ -804,16 +755,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics service.GetTestAccessor().WaitUntilCompletion(workspace, SpecializedCollections.SingletonEnumerable(analyzerService.CreateIncrementalAnalyzer(workspace)).WhereNotNull().ToImmutableArray()) End Sub - Private Function CreateItem(documentId As DocumentId, Optional severity As DiagnosticSeverity = DiagnosticSeverity.Error) As DiagnosticData + Private Shared Function CreateItem(documentId As DocumentId, Optional severity As DiagnosticSeverity = DiagnosticSeverity.Error) As DiagnosticData Return CreateItem(documentId.ProjectId, documentId, severity) End Function - Private Function CreateItem(projectId As ProjectId, documentId As DocumentId, Optional severity As DiagnosticSeverity = DiagnosticSeverity.Error, Optional link As String = Nothing) As DiagnosticData + Private Shared Function CreateItem(projectId As ProjectId, documentId As DocumentId, Optional severity As DiagnosticSeverity = DiagnosticSeverity.Error, Optional link As String = Nothing) As DiagnosticData Return New DiagnosticData( id:="test", category:="test", message:="test", - enuMessageForBingSearch:="test format", severity:=severity, defaultSeverity:=severity, isEnabledByDefault:=True, @@ -841,14 +791,14 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Public Function GetDiagnostics(workspace As Workspace, projectId As ProjectId, documentId As DocumentId, id As Object, includeSuppressedDiagnostics As Boolean, cancellationToken As CancellationToken) As ImmutableArray(Of DiagnosticData) Implements IDiagnosticService.GetDiagnostics - Return GetPushDiagnosticsAsync(workspace, projectId, documentId, id, includeSuppressedDiagnostics, InternalDiagnosticsOptions.NormalDiagnosticMode, cancellationToken).AsTask().WaitAndGetResult_CanCallOnBackground(cancellationToken) + Return GetPushDiagnosticsAsync(workspace, projectId, documentId, id, includeSuppressedDiagnostics, DiagnosticMode.Default, cancellationToken).AsTask().WaitAndGetResult_CanCallOnBackground(cancellationToken) End Function - Public Function GetPullDiagnosticsAsync(workspace As Workspace, projectId As ProjectId, documentId As DocumentId, id As Object, includeSuppressedDiagnostics As Boolean, diagnosticMode As Option2(Of DiagnosticMode), cancellationToken As CancellationToken) As ValueTask(Of ImmutableArray(Of DiagnosticData)) Implements IDiagnosticService.GetPullDiagnosticsAsync + Public Function GetPullDiagnosticsAsync(workspace As Workspace, projectId As ProjectId, documentId As DocumentId, id As Object, includeSuppressedDiagnostics As Boolean, diagnosticMode As DiagnosticMode, cancellationToken As CancellationToken) As ValueTask(Of ImmutableArray(Of DiagnosticData)) Implements IDiagnosticService.GetPullDiagnosticsAsync Return New ValueTask(Of ImmutableArray(Of DiagnosticData))(GetDiagnostics(workspace, projectId, documentId, includeSuppressedDiagnostics)) End Function - Public Function GetPushDiagnosticsAsync(workspace As Workspace, projectId As ProjectId, documentId As DocumentId, id As Object, includeSuppressedDiagnostics As Boolean, diagnosticMode As Option2(Of DiagnosticMode), cancellationToken As CancellationToken) As ValueTask(Of ImmutableArray(Of DiagnosticData)) Implements IDiagnosticService.GetPushDiagnosticsAsync + Public Function GetPushDiagnosticsAsync(workspace As Workspace, projectId As ProjectId, documentId As DocumentId, id As Object, includeSuppressedDiagnostics As Boolean, diagnosticMode As DiagnosticMode, cancellationToken As CancellationToken) As ValueTask(Of ImmutableArray(Of DiagnosticData)) Implements IDiagnosticService.GetPushDiagnosticsAsync Return New ValueTask(Of ImmutableArray(Of DiagnosticData))(GetDiagnostics(workspace, projectId, documentId, includeSuppressedDiagnostics)) End Function @@ -876,11 +826,11 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics Return diagnostics End Function - Public Function GetPullDiagnosticBuckets(workspace As Workspace, projectId As ProjectId, documentId As DocumentId, diagnosticMode As Option2(Of DiagnosticMode), cancellationToken As CancellationToken) As ImmutableArray(Of DiagnosticBucket) Implements IDiagnosticService.GetPullDiagnosticBuckets + Public Function GetPullDiagnosticBuckets(workspace As Workspace, projectId As ProjectId, documentId As DocumentId, diagnosticMode As DiagnosticMode, cancellationToken As CancellationToken) As ImmutableArray(Of DiagnosticBucket) Implements IDiagnosticService.GetPullDiagnosticBuckets Return GetDiagnosticsBuckets(workspace, projectId, documentId) End Function - Public Function GetPushDiagnosticBuckets(workspace As Workspace, projectId As ProjectId, documentId As DocumentId, diagnosticMode As Option2(Of DiagnosticMode), cancellationToken As CancellationToken) As ImmutableArray(Of DiagnosticBucket) Implements IDiagnosticService.GetPushDiagnosticBuckets + Public Function GetPushDiagnosticBuckets(workspace As Workspace, projectId As ProjectId, documentId As DocumentId, diagnosticMode As DiagnosticMode, cancellationToken As CancellationToken) As ImmutableArray(Of DiagnosticBucket) Implements IDiagnosticService.GetPushDiagnosticBuckets Return GetDiagnosticsBuckets(workspace, projectId, documentId) End Function diff --git a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb index cfcbe526af56d..240b7ac2dea93 100644 --- a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb +++ b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb @@ -398,7 +398,6 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics id:="CS1002", category:="Test", message:="Test Message", - enuMessageForBingSearch:="Test Message Format", severity:=DiagnosticSeverity.Error, defaultSeverity:=DiagnosticSeverity.Error, isEnabledByDefault:=True, @@ -471,13 +470,12 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics End Sub End Class - Private Function GetDiagnosticData(projectId As ProjectId, Optional isBuildDiagnostic As Boolean = False, Optional id As String = "id") As DiagnosticData + Private Shared Function GetDiagnosticData(projectId As ProjectId, Optional isBuildDiagnostic As Boolean = False, Optional id As String = "id") As DiagnosticData Dim properties = If(isBuildDiagnostic, DiagnosticData.PropertiesForBuildDiagnostic, ImmutableDictionary(Of String, String).Empty) Return New DiagnosticData( id, category:="Test", message:="Test Message", - enuMessageForBingSearch:="Test Message Format", severity:=DiagnosticSeverity.Error, defaultSeverity:=DiagnosticSeverity.Error, isEnabledByDefault:=True, diff --git a/src/VisualStudio/Core/Test/Diagnostics/TodoListTableDataSourceTests.vb b/src/VisualStudio/Core/Test/Diagnostics/TodoListTableDataSourceTests.vb index 8930912141cc7..bffc3c13d4839 100644 --- a/src/VisualStudio/Core/Test/Diagnostics/TodoListTableDataSourceTests.vb +++ b/src/VisualStudio/Core/Test/Diagnostics/TodoListTableDataSourceTests.vb @@ -359,7 +359,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics End Using End Sub - Private Function CreateItem(documentId As DocumentId) As TodoCommentData + Private Shared Function CreateItem(documentId As DocumentId) As TodoCommentData Return New TodoCommentData( priority:=0, message:="test", diff --git a/src/VisualStudio/Core/Test/ExtractInterface/ExtractInterfaceViewModelTests.vb b/src/VisualStudio/Core/Test/ExtractInterface/ExtractInterfaceViewModelTests.vb index a33a37365c65d..567a925a4bd19 100644 --- a/src/VisualStudio/Core/Test/ExtractInterface/ExtractInterfaceViewModelTests.vb +++ b/src/VisualStudio/Core/Test/ExtractInterface/ExtractInterfaceViewModelTests.vb @@ -272,7 +272,7 @@ public class $$MyClass Assert.Equal("Goo(string)", viewModel.MemberContainers.ElementAt(4).SymbolName) End Function - Private Async Function GetViewModelAsync(markup As XElement, + Private Shared Async Function GetViewModelAsync(markup As XElement, languageName As String, defaultInterfaceName As String, Optional defaultNamespace As String = "", diff --git a/src/VisualStudio/Core/Test/GenerateType/GenerateTypeViewModelTests.vb b/src/VisualStudio/Core/Test/GenerateType/GenerateTypeViewModelTests.vb index 023c6eba817e6..fd9150b56cfbf 100644 --- a/src/VisualStudio/Core/Test/GenerateType/GenerateTypeViewModelTests.vb +++ b/src/VisualStudio/Core/Test/GenerateType/GenerateTypeViewModelTests.vb @@ -806,12 +806,12 @@ namespace A File.Delete(pathString) End Function - Private Function PopulateProjectFolders(list As List(Of String), ParamArray values As String()) As List(Of String) + Private Shared Function PopulateProjectFolders(list As List(Of String), ParamArray values As String()) As List(Of String) list.AddRange(values) Return list End Function - Private Function GetOneProjectWorkspace( + Private Shared Function GetOneProjectWorkspace( documentContent As XElement, languageName As String, projectName As String, @@ -835,7 +835,7 @@ namespace A End If End Function - Private Async Function GetViewModelAsync( + Private Shared Async Function GetViewModelAsync( content As XElement, languageName As String, Optional isNewFile As Boolean = False, diff --git a/src/VisualStudio/Core/Test/GoToDefinition/GoToDefinitionApiTests.vb b/src/VisualStudio/Core/Test/GoToDefinition/GoToDefinitionApiTests.vb index 1d0a28b524af4..9ce7775dbaee4 100644 --- a/src/VisualStudio/Core/Test/GoToDefinition/GoToDefinitionApiTests.vb +++ b/src/VisualStudio/Core/Test/GoToDefinition/GoToDefinitionApiTests.vb @@ -16,7 +16,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.GoToDefinition <[UseExportProvider]> Public Class GoToDefinitionApiTests - Private Async Function TestAsync(workspaceDefinition As XElement, expectSuccess As Boolean) As Tasks.Task + Private Shared Async Function TestAsync(workspaceDefinition As XElement, expectSuccess As Boolean) As Tasks.Task Using workspace = TestWorkspace.Create(workspaceDefinition, composition:=GoToTestHelpers.Composition) Dim solution = workspace.CurrentSolution Dim cursorDocument = workspace.Documents.First(Function(d) d.CursorPosition.HasValue) @@ -54,7 +54,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.GoToDefinition End Using End Function - Private Function TestSuccessAsync(workspaceDefinition As XElement) As Tasks.Task + Private Shared Function TestSuccessAsync(workspaceDefinition As XElement) As Tasks.Task Return TestAsync(workspaceDefinition, True) End Function diff --git a/src/VisualStudio/Core/Test/LanguageBlockTests.vb b/src/VisualStudio/Core/Test/LanguageBlockTests.vb index 91b45c2e46dba..9cf336b2733d0 100644 --- a/src/VisualStudio/Core/Test/LanguageBlockTests.vb +++ b/src/VisualStudio/Core/Test/LanguageBlockTests.vb @@ -233,7 +233,7 @@ System.Console$$.WriteLine(message) ", LanguageNames.VisualBasic, SourceCodeKind.Regular) End Sub - Private Sub VerifyNoBlock(markup As String, languageName As String, Optional sourceCodeKind As SourceCodeKind = SourceCodeKind.Regular) + Private Shared Sub VerifyNoBlock(markup As String, languageName As String, Optional sourceCodeKind As SourceCodeKind = SourceCodeKind.Regular) Dim xml = CommonReferences="True"> @@ -257,7 +257,7 @@ System.Console$$.WriteLine(message) End Using End Sub - Private Sub VerifyBlock(markup As String, languageName As String, expectedDescription As String) + Private Shared Sub VerifyBlock(markup As String, languageName As String, expectedDescription As String) Dim xml = CommonReferences="True"> diff --git a/src/VisualStudio/Core/Test/MoveStaticMembers/MoveStaticMembersViewModelTest.vb b/src/VisualStudio/Core/Test/MoveStaticMembers/MoveStaticMembersViewModelTest.vb index 50861850c323e..779cb600722f4 100644 --- a/src/VisualStudio/Core/Test/MoveStaticMembers/MoveStaticMembersViewModelTest.vb +++ b/src/VisualStudio/Core/Test/MoveStaticMembers/MoveStaticMembersViewModelTest.vb @@ -18,7 +18,7 @@ Imports Microsoft.VisualStudio.Utilities Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.MoveStaticMembers Public Class MoveStaticMembersViewModelTest - Private Async Function GetViewModelAsync(xmlElement As XElement) As Task(Of MoveStaticMembersDialogViewModel) + Private Shared Async Function GetViewModelAsync(xmlElement As XElement) As Task(Of MoveStaticMembersDialogViewModel) Dim workspaceXml = xmlElement.Value Using workspace = TestWorkspace.Create(workspaceXml) Dim doc = workspace.Documents.ElementAt(0) @@ -40,20 +40,20 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.MoveStaticMembers End Using End Function - Private Function FindMemberByName(name As String, memberArray As ImmutableArray(Of SymbolViewModel(Of ISymbol))) As SymbolViewModel(Of ISymbol) + Private Shared Function FindMemberByName(name As String, memberArray As ImmutableArray(Of SymbolViewModel(Of ISymbol))) As SymbolViewModel(Of ISymbol) Dim member = memberArray.FirstOrDefault(Function(memberViewModel) memberViewModel.Symbol.Name.Equals(name)) Assert.NotNull(member) Return member End Function - Private Sub SelectMember(name As String, viewModel As StaticMemberSelectionViewModel) + Private Shared Sub SelectMember(name As String, viewModel As StaticMemberSelectionViewModel) Dim member = FindMemberByName(name, viewModel.Members) member.IsChecked = True viewModel.Members.Replace(FindMemberByName(name, viewModel.Members), member) Assert.True(FindMemberByName(name, viewModel.Members).IsChecked) End Sub - Private Sub DeselectMember(name As String, viewModel As StaticMemberSelectionViewModel) + Private Shared Sub DeselectMember(name As String, viewModel As StaticMemberSelectionViewModel) Dim member = FindMemberByName(name, viewModel.Members) member.IsChecked = False viewModel.Members.Replace(FindMemberByName(name, viewModel.Members), member) diff --git a/src/VisualStudio/Core/Test/MoveToNamespace/MoveToNamespaceDialogViewModelTests.vb b/src/VisualStudio/Core/Test/MoveToNamespace/MoveToNamespaceDialogViewModelTests.vb index 89559597f3149..01163b805c9bb 100644 --- a/src/VisualStudio/Core/Test/MoveToNamespace/MoveToNamespaceDialogViewModelTests.vb +++ b/src/VisualStudio/Core/Test/MoveToNamespace/MoveToNamespaceDialogViewModelTests.vb @@ -70,7 +70,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.MoveToNamespace Assert.False(viewModel.ShowMessage) End Sub - Private Function CreateViewModel(Optional defaultNamespace As String = Nothing, Optional availableNamespaces As ImmutableArray(Of String) = Nothing) As MoveToNamespaceDialogViewModel + Private Shared Function CreateViewModel(Optional defaultNamespace As String = Nothing, Optional availableNamespaces As ImmutableArray(Of String) = Nothing) As MoveToNamespaceDialogViewModel If (defaultNamespace Is Nothing) Then defaultNamespace = "Default.Namespace" End If diff --git a/src/VisualStudio/Core/Test/Preview/PreviewChangesTests.vb b/src/VisualStudio/Core/Test/Preview/PreviewChangesTests.vb index 0dc31574c7fb3..ba2de2657c189 100644 --- a/src/VisualStudio/Core/Test/Preview/PreviewChangesTests.vb +++ b/src/VisualStudio/Core/Test/Preview/PreviewChangesTests.vb @@ -357,19 +357,19 @@ End Class Next End Sub - Private Sub AssertChildCount(list As ChangeList, count As UInteger) + Private Shared Sub AssertChildCount(list As ChangeList, count As UInteger) Dim actualCount As UInteger = Nothing list.GetItemCount(actualCount) Assert.Equal(count, actualCount) End Sub - Private Sub AssertChildText(list As ChangeList, index As UInteger, text As String) + Private Shared Sub AssertChildText(list As ChangeList, index As UInteger, text As String) Dim actualText As String = Nothing list.GetText(index, Nothing, actualText) Assert.Equal(text, actualText) End Sub - Private Sub AssertSomeChild(list As ChangeList, text As String) + Private Shared Sub AssertSomeChild(list As ChangeList, text As String) Dim count As UInteger = Nothing list.GetItemCount(count) For i As UInteger = 0 To count diff --git a/src/VisualStudio/Core/Test/Progression/GraphNodeCreationTests.vb b/src/VisualStudio/Core/Test/Progression/GraphNodeCreationTests.vb index b4bba301206ae..1a3bb6183c6cc 100644 --- a/src/VisualStudio/Core/Test/Progression/GraphNodeCreationTests.vb +++ b/src/VisualStudio/Core/Test/Progression/GraphNodeCreationTests.vb @@ -14,7 +14,7 @@ Imports Roslyn.Test.Utilities Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Progression Public Class GraphNodeCreationTests - Private Async Function AssertCreatedNodeIsAsync(code As String, expectedId As String, xml As XElement, Optional language As String = "C#") As Task + Private Shared Async Function AssertCreatedNodeIsAsync(code As String, expectedId As String, xml As XElement, Optional language As String = "C#") As Task Using testState = ProgressionTestState.Create( CommonReferences="true" FilePath="Z:\Project.csproj"> diff --git a/src/VisualStudio/Core/Test/Progression/GraphNodeIdTests.vb b/src/VisualStudio/Core/Test/Progression/GraphNodeIdTests.vb index ca3e6d95253c0..ba45bd844b75b 100644 --- a/src/VisualStudio/Core/Test/Progression/GraphNodeIdTests.vb +++ b/src/VisualStudio/Core/Test/Progression/GraphNodeIdTests.vb @@ -11,7 +11,7 @@ Imports Roslyn.Test.Utilities Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Progression Public Class GraphNodeIdTests - Private Async Function AssertMarkedNodeIdIsAsync(code As String, expectedId As String, Optional language As String = "C#", Optional symbolTransform As Func(Of ISymbol, ISymbol) = Nothing) As Task + Private Shared Async Function AssertMarkedNodeIdIsAsync(code As String, expectedId As String, Optional language As String = "C#", Optional symbolTransform As Func(Of ISymbol, ISymbol) = Nothing) As Task Using testState = ProgressionTestState.Create( CommonReferences="true" FilePath="Z:\Project.csproj"> diff --git a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/AnalyzerReferenceTests.vb b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/AnalyzerReferenceTests.vb index ccf7714928bba..2c8986b3540f0 100644 --- a/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/AnalyzerReferenceTests.vb +++ b/src/VisualStudio/Core/Test/ProjectSystemShim/VisualStudioProjectTests/AnalyzerReferenceTests.vb @@ -120,7 +120,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim document:=Nothing, includeSuppressedDiagnostics:=True, forPullDiagnostics:=False, - InternalDiagnosticsOptions.NormalDiagnosticMode, + DiagnosticMode.Default, CancellationToken.None) Return diagnostics End Function diff --git a/src/VisualStudio/Core/Test/PullMemberUp/PullMemberUpViewModelTest.vb b/src/VisualStudio/Core/Test/PullMemberUp/PullMemberUpViewModelTest.vb index 88c32b9cc177a..99f64acc82a89 100644 --- a/src/VisualStudio/Core/Test/PullMemberUp/PullMemberUpViewModelTest.vb +++ b/src/VisualStudio/Core/Test/PullMemberUp/PullMemberUpViewModelTest.vb @@ -225,7 +225,7 @@ class MyClass : Level1BaseClass, Level1Interface Next End Function - Private Function FindMemberByName(name As String, memberArray As ImmutableArray(Of PullMemberUpSymbolViewModel)) As PullMemberUpSymbolViewModel + Private Shared Function FindMemberByName(name As String, memberArray As ImmutableArray(Of PullMemberUpSymbolViewModel)) As PullMemberUpSymbolViewModel Dim member = memberArray.FirstOrDefault(Function(memberViewModel) memberViewModel.SymbolName.Equals(name)) If (member Is Nothing) Then Assert.True(False, $"No member called {name} found") @@ -234,7 +234,7 @@ class MyClass : Level1BaseClass, Level1Interface Return member End Function - Private Async Function GetViewModelAsync(markup As XElement, languageName As String) As Task(Of PullMemberUpDialogViewModel) + Private Shared Async Function GetViewModelAsync(markup As XElement, languageName As String) As Task(Of PullMemberUpDialogViewModel) Dim workspaceXml = CommonReferences="true"> diff --git a/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb b/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb index 29031633262c7..fb7e0ff58146e 100644 --- a/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb +++ b/src/VisualStudio/Core/Test/Snippets/CSharpSnippetExpansionClientTests.vb @@ -5,10 +5,8 @@ Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.AddImport Imports Microsoft.CodeAnalysis.Completion -Imports Microsoft.CodeAnalysis.CSharp -Imports Microsoft.CodeAnalysis.CSharp.CodeGeneration -Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces @@ -355,7 +353,7 @@ using G= H.I; End Using End Sub - Private Async Function TestSnippetAddImportsAsync( + Private Shared Async Function TestSnippetAddImportsAsync( markupCode As String, namespacesToAdd As String(), placeSystemNamespaceFirst As Boolean, @@ -395,16 +393,16 @@ using G= H.I; workspace.GetService(Of IGlobalOptionService)) Dim document = workspace.CurrentSolution.Projects.Single().Documents.Single() - Dim options = Await document.GetOptionsAsync(CancellationToken.None).ConfigureAwait(False) - options = options.WithChangedOption(GenerationOptions.PlaceSystemNamespaceFirst, placeSystemNamespaceFirst) - Dim preferences = New CSharpCodeGenerationPreferences(CType(document.DocumentState.ParseOptions, CSharpParseOptions), options) + Dim options = New AddImportPlacementOptions( + PlaceSystemNamespaceFirst:=placeSystemNamespaceFirst, + PlaceImportsInsideNamespaces:=False, + AllowInHiddenRegions:=False) Dim updatedDocument = expansionClient.AddImports( document, - preferences, + options, If(position, 0), snippetNode, - allowInHiddenRegions:=False, CancellationToken.None) Assert.Equal(expectedUpdatedCode, diff --git a/src/VisualStudio/Core/Test/Snippets/SnippetCompletionProviderTests.vb b/src/VisualStudio/Core/Test/Snippets/SnippetCompletionProviderTests.vb index 2ac0f1111854a..b73c1b6bb3b15 100644 --- a/src/VisualStudio/Core/Test/Snippets/SnippetCompletionProviderTests.vb +++ b/src/VisualStudio/Core/Test/Snippets/SnippetCompletionProviderTests.vb @@ -82,8 +82,7 @@ End Class.Value Dim testState = SnippetTestState.CreateTestState(markup, LanguageNames.VisualBasic, extraParts:={GetType(MockSnippetInfoService)}) Using testState Dim workspace = testState.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(New Options.OptionKey(CompletionOptions.Metadata.SnippetsBehavior, LanguageNames.VisualBasic), SnippetsRule.AlwaysInclude))) + workspace.GlobalOptions.SetGlobalOption(New Options.OptionKey(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.VisualBasic), SnippetsRule.AlwaysInclude) testState.SendTypeChars("'T") Await testState.AssertNoCompletionSession() End Using @@ -100,8 +99,7 @@ End Class.Value Dim testState = SnippetTestState.CreateTestState(markup, LanguageNames.VisualBasic, extraParts:={GetType(MockSnippetInfoService)}) Using testState Dim workspace = testState.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(New Options.OptionKey(CompletionOptions.Metadata.SnippetsBehavior, LanguageNames.VisualBasic), SnippetsRule.AlwaysInclude))) + workspace.GlobalOptions.SetGlobalOption(New Options.OptionKey(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.VisualBasic), SnippetsRule.AlwaysInclude) testState.SendTypeChars("'''T") Await testState.AssertNoCompletionSession() End Using @@ -117,8 +115,7 @@ End Class.Value Dim testState = SnippetTestState.CreateTestState(markup, LanguageNames.VisualBasic, extraParts:={GetType(MockSnippetInfoService)}) Using testState Dim workspace = testState.Workspace - workspace.TryApplyChanges(workspace.CurrentSolution.WithOptions(workspace.Options _ - .WithChangedOption(New Options.OptionKey(CompletionOptions.Metadata.SnippetsBehavior, LanguageNames.VisualBasic), SnippetsRule.AlwaysInclude))) + workspace.GlobalOptions.SetGlobalOption(New Options.OptionKey(CompletionOptionsStorage.SnippetsBehavior, LanguageNames.VisualBasic), SnippetsRule.AlwaysInclude) testState.SendTypeChars("Shortcut") Await testState.AssertSelectedCompletionItem(displayText:="Shortcut") End Using diff --git a/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb b/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb index bec94616cc128..1601627634bf8 100644 --- a/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb +++ b/src/VisualStudio/Core/Test/Snippets/SnippetTestState.vb @@ -5,7 +5,7 @@ Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.CodeGeneration +Imports Microsoft.CodeAnalysis.AddImport Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Editor Imports Microsoft.CodeAnalysis.Editor.Implementation.Formatting @@ -206,10 +206,6 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets Return TryInsertExpansionReturnValue End Function - Public Overrides Function GetExpansionFunction(xmlFunctionNode As IXMLDOMNode, bstrFieldName As String, ByRef pFunc As IVsExpansionFunction) As Integer - Throw New NotImplementedException() - End Function - Protected Overrides Function InsertEmptyCommentAndGetEndPositionTrackingSpan() As ITrackingSpan Throw New NotImplementedException() End Function @@ -220,7 +216,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets End Get End Property - Friend Overrides Function AddImports(document As Document, preferences As CodeGenerationPreferences, position As Integer, snippetNode As XElement, allowInHiddenRegions As Boolean, cancellationToken As CancellationToken) As Document + Friend Overrides Function AddImports(document As Document, options As AddImportPlacementOptions, position As Integer, snippetNode As XElement, cancellationToken As CancellationToken) As Document Return document End Function End Class diff --git a/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb b/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb index 809838ea997d6..84e8d5513547c 100644 --- a/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb +++ b/src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb @@ -5,8 +5,8 @@ Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.AddImport Imports Microsoft.CodeAnalysis.Completion -Imports Microsoft.CodeAnalysis.Editing Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces @@ -14,7 +14,6 @@ Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Options Imports Microsoft.CodeAnalysis.Test.Utilities -Imports Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Imports Microsoft.VisualStudio.LanguageServices.VisualBasic.Snippets Imports Microsoft.VisualStudio.Text.Projection Imports Roslyn.Test.Utilities @@ -371,7 +370,7 @@ End Class End Using End Sub - Private Async Function TestSnippetAddImportsAsync( + Private Shared Async Function TestSnippetAddImportsAsync( markupCode As String, namespacesToAdd As String(), placeSystemNamespaceFirst As Boolean, @@ -412,16 +411,17 @@ End Class workspace.GetService(Of IGlobalOptionService)) Dim document = workspace.CurrentSolution.Projects.Single().Documents.Single() - Dim options = Await document.GetOptionsAsync(CancellationToken.None).ConfigureAwait(False) - options = options.WithChangedOption(GenerationOptions.PlaceSystemNamespaceFirst, placeSystemNamespaceFirst) - Dim preferences = New VisualBasicCodeGenerationPreferences(options) + + Dim options = New AddImportPlacementOptions( + PlaceSystemNamespaceFirst:=placeSystemNamespaceFirst, + PlaceImportsInsideNamespaces:=False, + AllowInHiddenRegions:=False) Dim updatedDocument = expansionClient.AddImports( document, - preferences, + options, If(position, 0), snippetNode, - allowInHiddenRegions:=False, CancellationToken.None) Assert.Equal(expectedUpdatedCode.Replace(vbLf, vbCrLf), diff --git a/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzerCommandHandlerTests.vb b/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzerCommandHandlerTests.vb index 74d4d73d3b99c..cecf3013b5228 100644 --- a/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzerCommandHandlerTests.vb +++ b/src/VisualStudio/Core/Test/SolutionExplorer/AnalyzerCommandHandlerTests.vb @@ -20,10 +20,10 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer category:="Test", defaultSeverity:=DiagnosticSeverity.Error, isEnabledByDefault:=True) - Dim diagnosticItem = New DiagnosticItem(Nothing, Nothing, descriptor, ReportDiagnostic.Error, LanguageNames.VisualBasic, Nothing) + Dim diagnosticItem = New DiagnosticItem(projectId:=Nothing, analyzerReference:=Nothing, descriptor, ReportDiagnostic.Error, commandHandler:=Nothing) - Dim handler = New AnalyzersCommandHandler(Nothing, Nothing, Nothing, AsynchronousOperationListenerProvider.NullProvider, Nothing) - Dim shown = handler.DiagnosticContextMenuController.ShowContextMenu({diagnosticItem}, Nothing) + Dim handler = New AnalyzersCommandHandler(tracker:=Nothing, analyzerReferenceManager:=Nothing, threadingContext:=Nothing, AsynchronousOperationListenerProvider.NullProvider, serviceProvider:=Nothing) + Dim shown = handler.DiagnosticContextMenuController.ShowContextMenu({diagnosticItem}, location:=Nothing) Assert.False(shown) End Sub End Class diff --git a/src/VisualStudio/Core/Test/SolutionExplorer/DiagnosticItemTests.vb b/src/VisualStudio/Core/Test/SolutionExplorer/DiagnosticItemTests.vb index 42f1b3f5ba2a7..967320b912796 100644 --- a/src/VisualStudio/Core/Test/SolutionExplorer/DiagnosticItemTests.vb +++ b/src/VisualStudio/Core/Test/SolutionExplorer/DiagnosticItemTests.vb @@ -13,7 +13,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer Public Sub Name() Dim descriptor = CreateDescriptor() - Dim diagnostic = New DiagnosticItem(Nothing, Nothing, descriptor, ReportDiagnostic.Error, LanguageNames.VisualBasic, Nothing) + Dim diagnostic = New DiagnosticItem(projectId:=Nothing, analyzerReference:=Nothing, descriptor, ReportDiagnostic.Error, commandHandler:=Nothing) Assert.Equal(expected:="TST0001: A test diagnostic", actual:=diagnostic.Text) End Sub @@ -22,7 +22,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer Public Sub BrowseObject() Dim descriptor = CreateDescriptor() - Dim diagnostic = New DiagnosticItem(Nothing, Nothing, descriptor, ReportDiagnostic.Info, LanguageNames.VisualBasic, Nothing) + Dim diagnostic = New DiagnosticItem(projectId:=Nothing, analyzerReference:=Nothing, descriptor, ReportDiagnostic.Info, commandHandler:=Nothing) Dim browseObject = DirectCast(diagnostic.GetBrowseObject(), DiagnosticItem.BrowseObject) Assert.Equal(expected:=SolutionExplorerShim.Diagnostic_Properties, actual:=browseObject.GetClassName()) diff --git a/src/VisualStudio/Core/Test/SymbolSearch/SymbolSearchUpdateEngineTests.vb b/src/VisualStudio/Core/Test/SymbolSearch/SymbolSearchUpdateEngineTests.vb index cce65c84b71bb..a6aa22e963421 100644 --- a/src/VisualStudio/Core/Test/SymbolSearch/SymbolSearchUpdateEngineTests.vb +++ b/src/VisualStudio/Core/Test/SymbolSearch/SymbolSearchUpdateEngineTests.vb @@ -636,11 +636,11 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SymbolSearch Returns(clientMock.Object) End Sub - Private Function CreateFullDatabaseClientMock() As Mock(Of IRemoteControlClient) + Private Shared Function CreateFullDatabaseClientMock() As Mock(Of IRemoteControlClient) Return CreateClientMock(CreateFullDownloadElementStream()) End Function - Private Function CreateClientMock(stream As Stream) As Mock(Of IRemoteControlClient) + Private Shared Function CreateClientMock(stream As Stream) As Mock(Of IRemoteControlClient) Dim clientMock = New Mock(Of IRemoteControlClient)(MockBehavior.Strict) ' Return a full database element when the service asks for it. @@ -651,13 +651,13 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SymbolSearch Return clientMock End Function - Private Function CreatePatchClientMock(Optional isUpToDate As Boolean = False, + Private Shared Function CreatePatchClientMock(Optional isUpToDate As Boolean = False, Optional isTooOld As Boolean = False, Optional contents As String = Nothing) As Mock(Of IRemoteControlClient) Return CreateClientMock(CreatePatchElementStream(isUpToDate, isTooOld, contents)) End Function - Private Function CreatePatchElementStream(Optional isUpToDate As Boolean = False, + Private Shared Function CreatePatchElementStream(Optional isUpToDate As Boolean = False, Optional isTooOld As Boolean = False, Optional contents As String = Nothing) As Stream Dim element = New XElement("Patch", @@ -668,7 +668,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SymbolSearch Return CreateStream(element) End Function - Private Function CreateFullDownloadElementStream() As Stream + Private Shared Function CreateFullDownloadElementStream() As Stream Dim saveStream = New MemoryStream() Dim zipStream = New DeflateStream(saveStream, CompressionMode.Compress) zipStream.Write(New Byte() {0}, 0, 1) @@ -679,7 +679,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SymbolSearch New XAttribute(SymbolSearchUpdateEngine.ContentAttributeName, contents))) End Function - Private Function CreateStream(element As XElement) As Stream + Private Shared Function CreateStream(element As XElement) As Stream Dim stream = New MemoryStream() element.Save(stream) stream.Position = 0 diff --git a/src/VisualStudio/Core/Test/Venus/AbstractContainedLanguageCodeSupportTests.vb b/src/VisualStudio/Core/Test/Venus/AbstractContainedLanguageCodeSupportTests.vb index 971f1f0b78722..aab91110a6e6b 100644 --- a/src/VisualStudio/Core/Test/Venus/AbstractContainedLanguageCodeSupportTests.vb +++ b/src/VisualStudio/Core/Test/Venus/AbstractContainedLanguageCodeSupportTests.vb @@ -26,7 +26,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Venus AssertValidId(id, Sub(value) Assert.False(value)) End Sub +#Disable Warning CA1822 ' Mark members as static - False positive due to https://github.com/dotnet/roslyn/issues/50582 Private Sub AssertValidId(id As String, assertion As Action(Of Boolean)) +#Enable Warning CA1822 Using workspace = TestWorkspace.Create( AssemblyName="Assembly" CommonReferences="true"> diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpCodeActions.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpCodeActions.cs index 1f62232afbef8..4e3ab447bff18 100644 --- a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpCodeActions.cs +++ b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpCodeActions.cs @@ -237,7 +237,7 @@ class C applyFix: true, fixAllScope: FixAllScope.Project); - Assert.Equal(expectedText, VisualStudio.Editor.GetText()); + AssertEx.EqualOrDiff(expectedText, VisualStudio.Editor.GetText()); /* * The second portion of this test modifier the existing .editorconfig file to configure the analyzer to the @@ -296,7 +296,7 @@ public int Y2 } }"; - Assert.Equal(expectedText, VisualStudio.Editor.GetText()); + AssertEx.EqualOrDiff(expectedText, VisualStudio.Editor.GetText()); } [CriticalWpfTheory] @@ -347,17 +347,16 @@ class D // Verify that applying a Fix All operation does not change generated files. // This is a regression test for correctness with respect to the design. SetUpEditor(markup); - VisualStudio.WaitForApplicationIdle(CancellationToken.None); VisualStudio.Editor.InvokeCodeActionList(); VisualStudio.Editor.Verify.CodeAction( "Remove Unnecessary Usings", applyFix: true, fixAllScope: scope); - Assert.Equal(expectedText, VisualStudio.Editor.GetText()); + AssertEx.EqualOrDiff(expectedText, VisualStudio.Editor.GetText()); VisualStudio.SolutionExplorer.OpenFile(new ProjectUtils.Project(ProjectName), "D.cs"); - Assert.Equal(generatedSource, VisualStudio.Editor.GetText()); + AssertEx.EqualOrDiff(generatedSource, VisualStudio.Editor.GetText()); // Verify that a Fix All in Document in the generated file still does nothing. // ⚠ This is a statement of the current behavior, and not a claim regarding correctness of the design. @@ -370,7 +369,7 @@ class D applyFix: true, fixAllScope: FixAllScope.Document); - Assert.Equal(generatedSource, VisualStudio.Editor.GetText()); + AssertEx.EqualOrDiff(generatedSource, VisualStudio.Editor.GetText()); // Verify that the code action can still be applied manually from within the generated file. // This is a regression test for correctness with respect to the design. @@ -381,7 +380,7 @@ class D applyFix: true, fixAllScope: null); - Assert.Equal(expectedGeneratedSource, VisualStudio.Editor.GetText()); + AssertEx.EqualOrDiff(expectedGeneratedSource, VisualStudio.Editor.GetText()); } [CriticalWpfTheory] @@ -426,17 +425,16 @@ class D // change. MarkupTestFile.GetPosition(markup, out var expectedText, out int _); SetUpEditor(markup); - VisualStudio.WaitForApplicationIdle(CancellationToken.None); VisualStudio.Editor.InvokeCodeActionList(); VisualStudio.Editor.Verify.CodeAction( "Remove Unnecessary Usings", applyFix: true, fixAllScope: scope); - Assert.Equal(expectedText, VisualStudio.Editor.GetText()); + AssertEx.EqualOrDiff(expectedText, VisualStudio.Editor.GetText()); VisualStudio.SolutionExplorer.OpenFile(new ProjectUtils.Project(ProjectName), "D.cs"); - Assert.Equal(expectedSecondFile, VisualStudio.Editor.GetText()); + AssertEx.EqualOrDiff(expectedSecondFile, VisualStudio.Editor.GetText()); } [WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)] @@ -470,6 +468,12 @@ static void Main(string[] args) public class P2 { }"); VisualStudio.Editor.SendKeys(VirtualKey.Backspace, VirtualKey.Backspace, "Stream"); + VisualStudio.Workspace.WaitForAllAsyncOperations( + Helper.HangMitigatingTimeout, + FeatureAttribute.Workspace, + FeatureAttribute.EventHookup, + FeatureAttribute.Rename, + FeatureAttribute.RenameTracking); VisualStudio.Editor.InvokeCodeActionList(); var expectedItems = new[] @@ -518,6 +522,12 @@ static void Main(string[] args) }"); VisualStudio.Editor.SendKeys(VirtualKey.Backspace, VirtualKey.Backspace, "Foober"); + VisualStudio.Workspace.WaitForAllAsyncOperations( + Helper.HangMitigatingTimeout, + FeatureAttribute.Workspace, + FeatureAttribute.EventHookup, + FeatureAttribute.Rename, + FeatureAttribute.RenameTracking); VisualStudio.Editor.InvokeCodeActionList(); var expectedItems = new[] @@ -716,6 +726,13 @@ public static void Main() }"; SetUpEditor(markup); + VisualStudio.Workspace.WaitForAllAsyncOperations( + Helper.HangMitigatingTimeout, + FeatureAttribute.Workspace, + FeatureAttribute.SolutionCrawler, + FeatureAttribute.DiagnosticService, + FeatureAttribute.ErrorSquiggles); + // Verify CS0168 warning in original code. VerifyDiagnosticInErrorList("Warning", VisualStudio); @@ -737,6 +754,13 @@ public static void Main() }; VisualStudio.Editor.Verify.CodeActions(expectedItems, applyFix: "Error", ensureExpectedItemsAreOrdered: true); + VisualStudio.Workspace.WaitForAllAsyncOperations( + Helper.HangMitigatingTimeout, + FeatureAttribute.Workspace, + FeatureAttribute.SolutionCrawler, + FeatureAttribute.DiagnosticService, + FeatureAttribute.ErrorSquiggles); + // Verify CS0168 is now reported as an error. VerifyDiagnosticInErrorList("Error", VisualStudio); diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpGoToBase.cs b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpGoToBase.cs new file mode 100644 index 0000000000000..dd22ee5c6dc46 --- /dev/null +++ b/src/VisualStudio/IntegrationTest/IntegrationTests/CSharp/CSharpGoToBase.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable disable + +using System; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.VisualStudio.IntegrationTest.Utilities; +using Microsoft.VisualStudio.Shell; +using Roslyn.Test.Utilities; +using Xunit; +using Xunit.Abstractions; +using ProjectUtils = Microsoft.VisualStudio.IntegrationTest.Utilities.Common.ProjectUtils; + +namespace Roslyn.VisualStudio.IntegrationTests.CSharp +{ + [Collection(nameof(SharedIntegrationHostFixture))] + public class CSharpGoToBase : AbstractEditorTest + { + protected override string LanguageName => LanguageNames.CSharp; + + public CSharpGoToBase(VisualStudioInstanceFactory instanceFactory) + : base(instanceFactory, nameof(CSharpGoToBase)) + { + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.GoToBase)] + public void GoToBaseFromMetadataAsSource() + { + var project = new ProjectUtils.Project(ProjectName); + VisualStudio.SolutionExplorer.AddFile(project, "C.cs"); + VisualStudio.SolutionExplorer.OpenFile(project, "C.cs"); + VisualStudio.Editor.SetText( +@"using System; + +class C +{ + public override string ToString() + { + return ""C""; + } +}"); + VisualStudio.Editor.PlaceCaret("ToString", charsOffset: -1); + VisualStudio.Editor.GoToBase("Object [from metadata]"); + VisualStudio.Editor.Verify.TextContains(@"public virtual string ToString$$()", assertCaretPosition: true); + } + } +} diff --git a/src/VisualStudio/IntegrationTest/IntegrationTests/Microsoft.VisualStudio.LanguageServices.IntegrationTests.csproj b/src/VisualStudio/IntegrationTest/IntegrationTests/Microsoft.VisualStudio.LanguageServices.IntegrationTests.csproj index edf25b4b891f7..bb87fc080d28b 100644 --- a/src/VisualStudio/IntegrationTest/IntegrationTests/Microsoft.VisualStudio.LanguageServices.IntegrationTests.csproj +++ b/src/VisualStudio/IntegrationTest/IntegrationTests/Microsoft.VisualStudio.LanguageServices.IntegrationTests.csproj @@ -25,7 +25,6 @@ - diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpCodeActions.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpCodeActions.cs new file mode 100644 index 0000000000000..8c6c23cb4a8b0 --- /dev/null +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpCodeActions.cs @@ -0,0 +1,911 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.Extensibility.Testing; +using Microsoft.VisualStudio.IntegrationTest.Utilities.Input; +using Roslyn.Test.Utilities; +using Roslyn.VisualStudio.IntegrationTests; +using Xunit; + +namespace Roslyn.VisualStudio.NewIntegrationTests.CSharp +{ + public class CSharpCodeActions : AbstractEditorTest + { + public CSharpCodeActions() + : base(nameof(CSharpCodeActions)) + { + } + + protected override string LanguageName => LanguageNames.CSharp; + + [IdeFact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)] + public async Task GenerateMethodInClosedFile() + { + var project = ProjectName; + await TestServices.SolutionExplorer.AddFileAsync(project, "Foo.cs", contents: @" +public class Foo +{ +} +", cancellationToken: HangMitigatingCancellationToken); + + await SetUpEditorAsync(@" +using System; + +public class Program +{ + public static void Main(string[] args) + { + Foo f = new Foo(); + f.Bar()$$ + } +} +", HangMitigatingCancellationToken); + + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync("Generate method 'Bar'", applyFix: true, cancellationToken: HangMitigatingCancellationToken); + await TestServices.SolutionVerifier.FileContentsAsync(project, "Foo.cs", @" +using System; + +public class Foo +{ + internal void Bar() + { + throw new NotImplementedException(); + } +} +", HangMitigatingCancellationToken); + } + + [IdeFact, Trait(Traits.Feature, Traits.Features.CodeActionsAddImport)] + public async Task AddUsingOnIncompleteMember() + { + // Need to ensure that incomplete member diagnostics run at high pri so that add-using can be + // triggered by them. + await SetUpEditorAsync(@" +class Program +{ + DateTime$$ +} +", HangMitigatingCancellationToken); + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync("using System;", cancellationToken: HangMitigatingCancellationToken); + } + + [IdeFact, Trait(Traits.Feature, Traits.Features.CodeActionsAddImport)] + public async Task FastDoubleInvoke() + { + // We want to invoke the first smart tag and then *immediately* try invoking the next. + // The next will happen to be the 'Simplify name' smart tag. We should be able + // to get it to invoke without any sort of waiting to happen. This helps address a bug + // we had where our asynchronous smart tags interfered with asynchrony in VS, which caused + // the second smart tag to not expand if you tried invoking it too quickly + await SetUpEditorAsync(@" +class Program +{ + static void Main(string[] args) + { + Exception $$ex = new System.ArgumentException(); + } +} +", HangMitigatingCancellationToken); + + // Suspend file change notification during code action application, since spurious file change notifications + // can cause silent failure to apply the code action if they occur within this block. + await using (var fileChangeRestorer = await TestServices.Shell.PauseFileChangesAsync(HangMitigatingCancellationToken)) + { + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync("using System;", applyFix: true, blockUntilComplete: true, cancellationToken: HangMitigatingCancellationToken); + } + + // Suspend file change notification during code action application, since spurious file change notifications + // can cause silent failure to apply the code action if they occur within this block. + await using (var fileChangeRestorer = await TestServices.Shell.PauseFileChangesAsync(HangMitigatingCancellationToken)) + { + await TestServices.Editor.InvokeCodeActionListWithoutWaitingAsync(HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync("Simplify name 'System.ArgumentException'", applyFix: true, blockUntilComplete: true, cancellationToken: HangMitigatingCancellationToken); + } + + await TestServices.EditorVerifier.TextContainsAsync( + @" +using System; + +class Program +{ + static void Main(string[] args) + { + Exception ex = new ArgumentException(); + } +}", cancellationToken: HangMitigatingCancellationToken); + } + + [IdeFact, Trait(Traits.Feature, Traits.Features.CodeActionsInvokeDelegateWithConditionalAccess)] + public async Task InvokeDelegateWithConditionalAccessMultipleTimes() + { + var markup = @" +using System; +class C +{ + public event EventHandler First; + public event EventHandler Second; + void RaiseFirst() + { + var temp1 = First; + if (temp1 != null) + { + temp1$$(this, EventArgs.Empty); + } + } + void RaiseSecond() + { + var temp2 = Second; + if (temp2 != null) + { + temp2(this, EventArgs.Empty); + } + } +}"; + MarkupTestFile.GetSpans(markup, out _, out ImmutableArray _); + + await SetUpEditorAsync(markup, HangMitigatingCancellationToken); + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync("Delegate invocation can be simplified.", applyFix: true, ensureExpectedItemsAreOrdered: true, blockUntilComplete: true, cancellationToken: HangMitigatingCancellationToken); + await TestServices.Editor.PlaceCaretAsync("temp2", 0, 0, extendSelection: false, selectBlock: false, HangMitigatingCancellationToken); + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync("Delegate invocation can be simplified.", applyFix: true, ensureExpectedItemsAreOrdered: true, blockUntilComplete: true, cancellationToken: HangMitigatingCancellationToken); + await TestServices.EditorVerifier.TextContainsAsync("First?.", cancellationToken: HangMitigatingCancellationToken); + await TestServices.EditorVerifier.TextContainsAsync("Second?.", cancellationToken: HangMitigatingCancellationToken); + } + + [IdeFact] + [Trait(Traits.Feature, Traits.Features.EditorConfig)] + [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] + [WorkItem(15003, "https://github.com/dotnet/roslyn/issues/15003")] + [WorkItem(19089, "https://github.com/dotnet/roslyn/issues/19089")] + public async Task ApplyEditorConfigAndFixAllOccurrences() + { + var markup = @" +class C +{ + public int X1 + { + get + { + $$return 3; + } + } + + public int Y1 => 5; + + public int X2 + { + get + { + return 3; + } + } + + public int Y2 => 5; +}"; + var expectedText = @" +class C +{ + public int X1 => 3; + + public int Y1 => 5; + + public int X2 => 3; + + public int Y2 => 5; +}"; + + await TestServices.SolutionExplorer.OpenFileAsync(ProjectName, "Class1.cs", HangMitigatingCancellationToken); + + /* + * The first portion of this test adds a .editorconfig file to configure the analyzer behavior, and verifies + * that diagnostics appear automatically in response to the newly-created file. A fix all operation is + * applied, and the result is verified against the expected outcome for the .editorconfig style. + */ + + MarkupTestFile.GetSpans(markup, out _, out ImmutableArray _); + await SetUpEditorAsync(markup, HangMitigatingCancellationToken); + await TestServices.Workspace.WaitForAllAsyncOperationsAsync( + new[] + { + FeatureAttribute.Workspace, + FeatureAttribute.SolutionCrawler, + FeatureAttribute.DiagnosticService, + FeatureAttribute.ErrorSquiggles + }, + HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionsNotShowingAsync(HangMitigatingCancellationToken); + + var editorConfig = @"root = true + +[*.cs] +csharp_style_expression_bodied_properties = true:warning +"; + + await TestServices.SolutionExplorer.AddFileAsync(ProjectName, ".editorconfig", editorConfig, open: false, HangMitigatingCancellationToken); + + await TestServices.Workspace.WaitForAllAsyncOperationsAsync( + new[] + { + FeatureAttribute.Workspace, + FeatureAttribute.SolutionCrawler, + FeatureAttribute.DiagnosticService, + FeatureAttribute.ErrorSquiggles + }, + HangMitigatingCancellationToken); + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync( + "Use expression body for properties", + applyFix: true, + fixAllScope: FixAllScope.Project, + cancellationToken: HangMitigatingCancellationToken); + + AssertEx.EqualOrDiff(expectedText, await TestServices.Editor.GetTextAsync(HangMitigatingCancellationToken)); + + /* + * The second portion of this test modifier the existing .editorconfig file to configure the analyzer to the + * opposite style of the initial configuration, and verifies that diagnostics update automatically in + * response to the changes. A fix all operation is applied, and the result is verified against the expected + * outcome for the modified .editorconfig style. + */ + + await TestServices.SolutionExplorer.SetFileContentsAsync(ProjectName, ".editorconfig", editorConfig.Replace("true:warning", "false:warning"), HangMitigatingCancellationToken); + + await TestServices.Workspace.WaitForAllAsyncOperationsAsync( + new[] + { + FeatureAttribute.Workspace, + FeatureAttribute.SolutionCrawler, + FeatureAttribute.DiagnosticService, + FeatureAttribute.ErrorSquiggles + }, + HangMitigatingCancellationToken); + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync( + "Use block body for properties", + applyFix: true, + fixAllScope: FixAllScope.Project, + cancellationToken: HangMitigatingCancellationToken); + + expectedText = @" +class C +{ + public int X1 + { + get + { + return 3; + } + } + + public int Y1 + { + get + { + return 5; + } + } + + public int X2 + { + get + { + return 3; + } + } + + public int Y2 + { + get + { + return 5; + } + } +}"; + + AssertEx.EqualOrDiff(expectedText, await TestServices.Editor.GetTextAsync(HangMitigatingCancellationToken)); + } + + [CriticalIdeTheory] + [InlineData(FixAllScope.Project)] + [InlineData(FixAllScope.Solution)] + [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] + [WorkItem(33507, "https://github.com/dotnet/roslyn/issues/33507")] + public async Task FixAllOccurrencesIgnoresGeneratedCode(FixAllScope scope) + { + var markup = @" +using System; +using $$System.Threading; + +class C +{ + public IntPtr X1 { get; set; } +}"; + var expectedText = @" +using System; + +class C +{ + public IntPtr X1 { get; set; } +}"; + var generatedSourceMarkup = @"// +using System; +using $$System.Threading; + +class D +{ + public IntPtr X1 { get; set; } +}"; + var expectedGeneratedSource = @"// +using System; + +class D +{ + public IntPtr X1 { get; set; } +}"; + + MarkupTestFile.GetPosition(generatedSourceMarkup, out var generatedSource, out int generatedSourcePosition); + + await TestServices.SolutionExplorer.AddFileAsync(ProjectName, "D.cs", generatedSource, open: false, HangMitigatingCancellationToken); + + // Switch to the main document we'll be editing + await TestServices.SolutionExplorer.OpenFileAsync(ProjectName, "Class1.cs", HangMitigatingCancellationToken); + + // Verify that applying a Fix All operation does not change generated files. + // This is a regression test for correctness with respect to the design. + await SetUpEditorAsync(markup, HangMitigatingCancellationToken); + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync( + "Remove Unnecessary Usings", + applyFix: true, + fixAllScope: scope, + cancellationToken: HangMitigatingCancellationToken); + + AssertEx.EqualOrDiff(expectedText, await TestServices.Editor.GetTextAsync(HangMitigatingCancellationToken)); + + await TestServices.SolutionExplorer.OpenFileAsync(ProjectName, "D.cs", HangMitigatingCancellationToken); + AssertEx.EqualOrDiff(generatedSource, await TestServices.Editor.GetTextAsync(HangMitigatingCancellationToken)); + + // Verify that a Fix All in Document in the generated file still does nothing. + // ⚠ This is a statement of the current behavior, and not a claim regarding correctness of the design. + // The current behavior is observable; any change to this behavior should be part of an intentional design + // change. + await TestServices.Editor.MoveCaretAsync(generatedSourcePosition, HangMitigatingCancellationToken); + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync( + "Remove Unnecessary Usings", + applyFix: true, + fixAllScope: FixAllScope.Document, + cancellationToken: HangMitigatingCancellationToken); + + AssertEx.EqualOrDiff(generatedSource, await TestServices.Editor.GetTextAsync(HangMitigatingCancellationToken)); + + // Verify that the code action can still be applied manually from within the generated file. + // This is a regression test for correctness with respect to the design. + await TestServices.Editor.MoveCaretAsync(generatedSourcePosition, HangMitigatingCancellationToken); + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync( + "Remove Unnecessary Usings", + applyFix: true, + fixAllScope: null, + cancellationToken: HangMitigatingCancellationToken); + + AssertEx.EqualOrDiff(expectedGeneratedSource, await TestServices.Editor.GetTextAsync(HangMitigatingCancellationToken)); + } + + [CriticalIdeTheory] + [InlineData(FixAllScope.Project)] + [InlineData(FixAllScope.Solution)] + [Trait(Traits.Feature, Traits.Features.CodeActionsFixAllOccurrences)] + [WorkItem(33507, "https://github.com/dotnet/roslyn/issues/33507")] + public async Task FixAllOccurrencesTriggeredFromGeneratedCode(FixAllScope scope) + { + var markup = @"// +using System; +using $$System.Threading; + +class C +{ + public IntPtr X1 { get; set; } +}"; + var secondFile = @" +using System; +using System.Threading; + +class D +{ + public IntPtr X1 { get; set; } +}"; + var expectedSecondFile = @" +using System; + +class D +{ + public IntPtr X1 { get; set; } +}"; + + await TestServices.SolutionExplorer.AddFileAsync(ProjectName, "D.cs", secondFile, open: false, HangMitigatingCancellationToken); + + // Switch to the main document we'll be editing + await TestServices.SolutionExplorer.OpenFileAsync(ProjectName, "Class1.cs", HangMitigatingCancellationToken); + + // Verify that applying a Fix All operation does not change generated file, but does change other files. + // ⚠ This is a statement of the current behavior, and not a claim regarding correctness of the design. + // The current behavior is observable; any change to this behavior should be part of an intentional design + // change. + MarkupTestFile.GetPosition(markup, out var expectedText, out int _); + await SetUpEditorAsync(markup, HangMitigatingCancellationToken); + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync( + "Remove Unnecessary Usings", + applyFix: true, + fixAllScope: scope, + cancellationToken: HangMitigatingCancellationToken); + + AssertEx.EqualOrDiff(expectedText, await TestServices.Editor.GetTextAsync(HangMitigatingCancellationToken)); + + await TestServices.SolutionExplorer.OpenFileAsync(ProjectName, "D.cs", HangMitigatingCancellationToken); + AssertEx.EqualOrDiff(expectedSecondFile, await TestServices.Editor.GetTextAsync(HangMitigatingCancellationToken)); + } + + [IdeFact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)] + public async Task ClassificationInPreviewPane() + { + await SetUpEditorAsync(@" +class Program +{ + int Main() + { + Foo$$(); + } +}", HangMitigatingCancellationToken); + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + var classifiedTokens = await TestServices.Editor.GetLightBulbPreviewClassificationsAsync("Generate method 'Foo'", HangMitigatingCancellationToken); + Assert.True(classifiedTokens.Any(c => c.Span.GetText().ToString() == "void" && c.ClassificationType.Classification == "keyword")); + } + + [IdeFact, Trait(Traits.Feature, Traits.Features.CodeActionsAddImport)] + public async Task AddUsingExactMatchBeforeRenameTracking() + { + await SetUpEditorAsync(@" +public class Program +{ + static void Main(string[] args) + { + P2$$ p; + } +} + +public class P2 { }", HangMitigatingCancellationToken); + + await TestServices.Input.SendAsync(VirtualKey.Backspace, VirtualKey.Backspace, "Stream"); + await TestServices.Workspace.WaitForAllAsyncOperationsAsync( + new[] + { + FeatureAttribute.Workspace, + FeatureAttribute.EventHookup, + FeatureAttribute.Rename, + FeatureAttribute.RenameTracking, + FeatureAttribute.SolutionCrawler, + FeatureAttribute.DiagnosticService, + FeatureAttribute.ErrorSquiggles, + }, + HangMitigatingCancellationToken); + + // Suspend file change notification during code action application, since spurious file change notifications + // can cause silent failure to apply the code action if they occur within this block. + await using (var fileChangeRestorer = await TestServices.Shell.PauseFileChangesAsync(HangMitigatingCancellationToken)) + { + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + var expectedItems = new[] + { + "using System.IO;", + "Rename 'P2' to 'Stream'", + "System.IO.Stream", + "Generate class 'Stream' in new file", + "Generate class 'Stream'", + "Generate nested class 'Stream'", + "Generate new type...", + "Remove unused variable", + "Suppress or Configure issues", + "Suppress CS0168", + "in Source", + "Configure CS0168 severity", + "None", + "Silent", + "Suggestion", + "Warning", + "Error", + }; + + await TestServices.EditorVerifier.CodeActionsAsync(expectedItems, applyFix: expectedItems[0], ensureExpectedItemsAreOrdered: true, cancellationToken: HangMitigatingCancellationToken); + } + + await TestServices.EditorVerifier.TextContainsAsync("using System.IO;", cancellationToken: HangMitigatingCancellationToken); + } + + [IdeFact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateType)] + public async Task GFUFuzzyMatchAfterRenameTrackingAndAfterGenerateType() + { + await SetUpEditorAsync(@" +namespace N +{ + class Goober { } +} + +namespace NS +{ + public class P2 + { + static void Main(string[] args) + { + P2$$ p; + } + } +}", HangMitigatingCancellationToken); + await TestServices.Input.SendAsync(VirtualKey.Backspace, VirtualKey.Backspace, + "Foober"); + await TestServices.Workspace.WaitForAllAsyncOperationsAsync( + new[] + { + FeatureAttribute.Workspace, + FeatureAttribute.EventHookup, + FeatureAttribute.Rename, + FeatureAttribute.RenameTracking, + FeatureAttribute.SolutionCrawler, + FeatureAttribute.DiagnosticService, + FeatureAttribute.ErrorSquiggles, + }, + HangMitigatingCancellationToken); + + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + var expectedItems = new[] + { + "Rename 'P2' to 'Foober'", + "Generate class 'Foober' in new file", + "Generate class 'Foober'", + "Generate nested class 'Foober'", + "Generate new type...", + "Goober - using N;", + "Suppress or Configure issues", + "Suppress CS0168", + "in Source", + "Configure CS0168 severity", + "None", + "Silent", + "Suggestion", + "Warning", + "Error", + }; + + await TestServices.EditorVerifier.CodeActionsAsync(expectedItems, applyFix: expectedItems[0], ensureExpectedItemsAreOrdered: true, cancellationToken: HangMitigatingCancellationToken); + } + + [IdeFact, Trait(Traits.Feature, Traits.Features.CodeGeneration)] + public async Task SuppressionAfterRefactorings() + { + await SetUpEditorAsync(@" +[System.Obsolete] +class C +{ +} +class Program +{ + static void Main(string[] args) + { + C p = $$2; + } +}", HangMitigatingCancellationToken); + await TestServices.Editor.SelectTextInCurrentDocumentAsync("2", HangMitigatingCancellationToken); + + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + + var generateImplicitTitle = "Generate implicit conversion operator in 'C'"; + var expectedItems = new[] + { + "Introduce constant for '2'", + "Introduce constant for all occurrences of '2'", + "Introduce local constant for '2'", + "Introduce local constant for all occurrences of '2'", + "Extract method", + generateImplicitTitle, + "Suppress or Configure issues", + "Suppress CS0612", + "in Source", + "Configure CS0612 severity", + "None", + "Silent", + "Suggestion", + "Warning", + "Error", + }; + + await TestServices.EditorVerifier.CodeActionsAsync(expectedItems, applyFix: generateImplicitTitle, ensureExpectedItemsAreOrdered: true, cancellationToken: HangMitigatingCancellationToken); + await TestServices.EditorVerifier.TextContainsAsync("implicit", cancellationToken: HangMitigatingCancellationToken); + } + + [IdeFact, Trait(Traits.Feature, Traits.Features.CodeActionsAddImport)] + public async Task OrderFixesByCursorProximityLeft() + { + await SetUpEditorAsync(@" +using System; +public class Program +{ + static void Main(string[] args) + { + Byte[] bytes = null; + GCHandle$$ handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); + } +}", HangMitigatingCancellationToken); + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + var expectedItems = new[] + { + "using System.Runtime.InteropServices;", + "System.Runtime.InteropServices.GCHandle" + }; + + await TestServices.EditorVerifier.CodeActionsAsync(expectedItems, applyFix: expectedItems[0], ensureExpectedItemsAreOrdered: true, cancellationToken: HangMitigatingCancellationToken); + await TestServices.EditorVerifier.TextContainsAsync("using System.Runtime.InteropServices", cancellationToken: HangMitigatingCancellationToken); + } + + [IdeFact, Trait(Traits.Feature, Traits.Features.CodeActionsAddImport)] + public async Task OrderFixesByCursorProximityRight() + { + await SetUpEditorAsync(@" +using System; +public class Program +{ + static void Main(string[] args) + { + Byte[] bytes = null; + GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.$$Pinned); + } +}", HangMitigatingCancellationToken); + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + var expectedItems = new[] + { + "using System.Runtime.InteropServices;", + "System.Runtime.InteropServices.GCHandle" + }; + + await TestServices.EditorVerifier.CodeActionsAsync(expectedItems, applyFix: expectedItems[0], ensureExpectedItemsAreOrdered: true, cancellationToken: HangMitigatingCancellationToken); + await TestServices.EditorVerifier.TextContainsAsync("using System.Runtime.InteropServices", cancellationToken: HangMitigatingCancellationToken); + } + + [IdeFact, Trait(Traits.Feature, Traits.Features.CodeActionsConfiguration)] + public async Task ConfigureCodeStyleOptionValueAndSeverity() + { + await SetUpEditorAsync(@" +using System; +public class Program +{ + static void Main(string[] args) + { + var $$x = new Program(); + } +}", HangMitigatingCancellationToken); + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + var expectedItems = new[] + { + "Use discard '__'", // IDE0059 + "Use explicit type instead of 'var'", // IDE0008 + "Introduce local", + "Introduce local for 'new Program()'", + "Introduce local for all occurrences of 'new Program()'", + "Suppress or Configure issues", + "Configure IDE0008 code style", + "csharp__style__var__elsewhere", + "true", + "false", + "csharp__style__var__for__built__in__types", + "true", + "false", + "csharp__style__var__when__type__is__apparent", + "true", + "false", + "Configure IDE0008 severity", + "None", + "Silent", + "Suggestion", + "Warning", + "Error", + "Suppress IDE0059", + "in Source", + "in Suppression File", + "in Source (attribute)", + "Configure IDE0059 code style", + "unused__local__variable", + "discard__variable", + "Configure IDE0059 severity", + "None", + "Silent", + "Suggestion", + "Warning", + "Error", + "Configure severity for all 'Style' analyzers", + "None", + "Silent", + "Suggestion", + "Warning", + "Error", + "Configure severity for all analyzers", + "None", + "Silent", + "Suggestion", + "Warning", + "Error", + }; + + await TestServices.EditorVerifier.CodeActionsAsync(expectedItems, ensureExpectedItemsAreOrdered: true, cancellationToken: HangMitigatingCancellationToken); + } + + [IdeFact, Trait(Traits.Feature, Traits.Features.CodeActionsConfiguration)] + [WorkItem(46784, "https://github.com/dotnet/roslyn/issues/46784")] + public async Task ConfigureSeverity() + { + var markup = @" +class C +{ + public static void Main() + { + // CS0168: The variable 'x' is declared but never used + int $$x; + } +}"; + await SetUpEditorAsync(markup, HangMitigatingCancellationToken); + + await TestServices.Workspace.WaitForAllAsyncOperationsAsync( + new[] + { + FeatureAttribute.Workspace, + FeatureAttribute.SolutionCrawler, + FeatureAttribute.DiagnosticService, + FeatureAttribute.ErrorSquiggles, + }, + HangMitigatingCancellationToken); + + // Verify CS0168 warning in original code. + await VerifyDiagnosticInErrorListAsync("warning", TestServices, HangMitigatingCancellationToken); + + // Apply configuration severity fix to change CS0168 to be an error. + await SetUpEditorAsync(markup, HangMitigatingCancellationToken); + + // Suspend file change notification during code action application, since spurious file change notifications + // can cause silent failure to apply the code action if they occur within this block. + await using (var fileChangeRestorer = await TestServices.Shell.PauseFileChangesAsync(HangMitigatingCancellationToken)) + { + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + var expectedItems = new[] + { + "Remove unused variable", + "Suppress or Configure issues", + "Suppress CS0168", + "in Source", + "Configure CS0168 severity", + "None", + "Silent", + "Suggestion", + "Warning", + "Error", + }; + await TestServices.EditorVerifier.CodeActionsAsync(expectedItems, applyFix: "Error", ensureExpectedItemsAreOrdered: true, cancellationToken: HangMitigatingCancellationToken); + } + + await TestServices.Workspace.WaitForAllAsyncOperationsAsync( + new[] + { + FeatureAttribute.Workspace, + FeatureAttribute.SolutionCrawler, + FeatureAttribute.DiagnosticService, + FeatureAttribute.ErrorSquiggles, + }, + HangMitigatingCancellationToken); + + // Verify CS0168 is now reported as an error. + await VerifyDiagnosticInErrorListAsync("error", TestServices, HangMitigatingCancellationToken); + + static async Task VerifyDiagnosticInErrorListAsync(string expectedSeverity, TestServices testServices, CancellationToken cancellationToken) + { + await testServices.ErrorList.ShowErrorListAsync(cancellationToken); + string[] expectedContents = + { + $"(Compiler) Class1.cs(7, 13): {expectedSeverity} CS0168: The variable 'x' is declared but never used", + }; + + var actualContents = await testServices.ErrorList.GetErrorsAsync(cancellationToken); + AssertEx.EqualOrDiff( + string.Join(Environment.NewLine, expectedContents), + string.Join(Environment.NewLine, actualContents)); + } + } + + [IdeFact, Trait(Traits.Feature, Traits.Features.CodeActionsConfiguration)] + [WorkItem(46784, "https://github.com/dotnet/roslyn/issues/46784")] + public async Task ConfigureSeverityWithManualEditsToEditorconfig() + { + var markup = @" +class C +{ + public static void Main() + { + // CS0168: The variable 'x' is declared but never used + int $$x; + } +}"; + await SetUpEditorAsync(markup, HangMitigatingCancellationToken); + + await TestServices.Workspace.WaitForAllAsyncOperationsAsync( + new[] + { + FeatureAttribute.Workspace, + FeatureAttribute.SolutionCrawler, + FeatureAttribute.DiagnosticService, + FeatureAttribute.ErrorSquiggles, + }, + HangMitigatingCancellationToken); + + // Verify CS0168 warning in original code. + await VerifyDiagnosticInErrorListAsync("warning", TestServices, HangMitigatingCancellationToken); + + // Add an .editorconfig file to the project to change severity to error. + await TestServices.SolutionExplorer.AddFileAsync(ProjectName, ".editorconfig", open: true, cancellationToken: HangMitigatingCancellationToken); + await TestServices.Input.SendAsync(@" +[*.cs] +dotnet_diagnostic.CS0168.severity = "); + + // NOTE: Below wait is a critical step in repro-ing the original regression. + await TestServices.Workspace.WaitForAllAsyncOperationsAsync( + new[] + { + FeatureAttribute.Workspace, + FeatureAttribute.SolutionCrawler, + FeatureAttribute.DiagnosticService, + FeatureAttribute.ErrorSquiggles, + }, + HangMitigatingCancellationToken); + + await TestServices.Input.SendAsync("error"); + + await TestServices.Workspace.WaitForAllAsyncOperationsAsync( + new[] + { + FeatureAttribute.Workspace, + FeatureAttribute.SolutionCrawler, + FeatureAttribute.DiagnosticService, + FeatureAttribute.ErrorSquiggles, + }, + HangMitigatingCancellationToken); + + // Verify CS0168 is now reported as an error. + await VerifyDiagnosticInErrorListAsync("error", TestServices, HangMitigatingCancellationToken); + + static async Task VerifyDiagnosticInErrorListAsync(string expectedSeverity, TestServices testServices, CancellationToken cancellationToken) + { + await testServices.ErrorList.ShowErrorListAsync(cancellationToken); + string[] expectedContents = + { + $"(Compiler) Class1.cs(7, 13): {expectedSeverity} CS0168: The variable 'x' is declared but never used", + }; + + var actualContents = await testServices.ErrorList.GetErrorsAsync(cancellationToken); + AssertEx.EqualOrDiff( + string.Join(Environment.NewLine, expectedContents), + string.Join(Environment.NewLine, actualContents)); + } + } + } +} diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpFindReferences.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpFindReferences.cs new file mode 100644 index 0000000000000..d1cc40e26a9f9 --- /dev/null +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CSharp/CSharpFindReferences.cs @@ -0,0 +1,192 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation 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; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.CodeAnalysis.Storage; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.VisualStudio.IntegrationTest.Utilities.Input; +using Microsoft.VisualStudio.LanguageServices; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Shell.TableManager; +using Roslyn.VisualStudio.IntegrationTests; +using Xunit; + +namespace Roslyn.VisualStudio.NewIntegrationTests.CSharp +{ + [Trait(Traits.Feature, Traits.Features.FindReferences)] + public class CSharpFindReferences : AbstractEditorTest + { + public CSharpFindReferences() + : base(nameof(CSharpFindReferences)) + { + } + + protected override string LanguageName => LanguageNames.CSharp; + + [IdeFact] + public async Task FindReferencesToCtor() + { + await SetUpEditorAsync(@" +class Program +{ +}$$ +", HangMitigatingCancellationToken); + await TestServices.SolutionExplorer.AddFileAsync(ProjectName, "File2.cs", cancellationToken: HangMitigatingCancellationToken); + await TestServices.SolutionExplorer.OpenFileAsync(ProjectName, "File2.cs", HangMitigatingCancellationToken); + + await SetUpEditorAsync(@" +class SomeOtherClass +{ + void M() + { + Program p = new Progr$$am(); + } +} +", HangMitigatingCancellationToken); + + await TestServices.Input.SendAsync(new KeyPress(VirtualKey.F12, ShiftState.Shift)); + + const string ProgramReferencesCaption = "'Program' references"; + var results = await TestServices.FindReferencesWindow.GetContentsAsync(ProgramReferencesCaption, HangMitigatingCancellationToken); + + var activeWindowCaption = await TestServices.Shell.GetActiveWindowCaptionAsync(HangMitigatingCancellationToken); + Assert.Equal(expected: ProgramReferencesCaption, actual: activeWindowCaption); + + Assert.Collection( + results, + new Action[] + { + reference => + { + Assert.Equal(expected: "class Program", actual: reference.TryGetValue(StandardTableKeyNames.Text, out string code) ? code : null); + Assert.Equal(expected: 1, actual: reference.TryGetValue(StandardTableKeyNames.Line, out int line) ? line : -1); + Assert.Equal(expected: 6, actual: reference.TryGetValue(StandardTableKeyNames.Column, out int column) ? column : -1); + }, + reference => + { + Assert.Equal(expected: "Program p = new Program();", actual: reference.TryGetValue(StandardTableKeyNames.Text, out string code) ? code : null); + Assert.Equal(expected: 5, actual: reference.TryGetValue(StandardTableKeyNames.Line, out int line) ? line : -1); + Assert.Equal(expected: 24, actual: reference.TryGetValue(StandardTableKeyNames.Column, out int column) ? column : -1); + } + }); + + results[0].NavigateTo(isPreview: false, shouldActivate: true); + await WaitForNavigateAsync(HangMitigatingCancellationToken); + + // Assert we are in the right file now + Assert.Equal("Class1.cs*", await TestServices.Shell.GetActiveWindowCaptionAsync(HangMitigatingCancellationToken)); + Assert.Equal("Program", await TestServices.Editor.GetLineTextAfterCaretAsync(HangMitigatingCancellationToken)); + } + + [IdeFact] + public async Task FindReferencesToLocals() + { + await using var telemetry = await TestServices.Telemetry.EnableTestTelemetryChannelAsync(HangMitigatingCancellationToken); + await SetUpEditorAsync(@" +class Program +{ + static void Main() + { + int local = 1; + Console.WriteLine(local$$); + } +} +", HangMitigatingCancellationToken); + + await TestServices.Input.SendAsync(new KeyPress(VirtualKey.F12, ShiftState.Shift)); + + const string LocalReferencesCaption = "'local' references"; + var results = await TestServices.FindReferencesWindow.GetContentsAsync(LocalReferencesCaption, HangMitigatingCancellationToken); + + var activeWindowCaption = await TestServices.Shell.GetActiveWindowCaptionAsync(HangMitigatingCancellationToken); + Assert.Equal(expected: LocalReferencesCaption, actual: activeWindowCaption); + + Assert.Collection( + results, + new Action[] + { + reference => + { + Assert.Equal(expected: "int local = 1;", actual: reference.TryGetValue(StandardTableKeyNames.Text, out string code) ? code : null); + Assert.Equal(expected: 5, actual: reference.TryGetValue(StandardTableKeyNames.Line, out int line) ? line : -1); + Assert.Equal(expected: 12, actual: reference.TryGetValue(StandardTableKeyNames.Column, out int column) ? column : -1); + }, + reference => + { + Assert.Equal(expected: "Console.WriteLine(local);", actual: reference.TryGetValue(StandardTableKeyNames.Text, out string code) ? code : null); + Assert.Equal(expected: 6, actual: reference.TryGetValue(StandardTableKeyNames.Line, out int line) ? line : -1); + Assert.Equal(expected: 26, actual: reference.TryGetValue(StandardTableKeyNames.Column, out int column) ? column : -1); + } + }); + + await telemetry.VerifyFiredAsync(new[] { "vs/platform/findallreferences/search", "vs/ide/vbcs/commandhandler/findallreference" }, HangMitigatingCancellationToken); + } + + [IdeFact] + public async Task FindReferencesToString() + { + await SetUpEditorAsync(@" +class Program +{ + static void Main() + { + string local = ""1""$$; + } +} +", HangMitigatingCancellationToken); + + await TestServices.Input.SendAsync(new KeyPress(VirtualKey.F12, ShiftState.Shift)); + + const string FindReferencesCaption = "'\"1\"' references"; + var results = await TestServices.FindReferencesWindow.GetContentsAsync(FindReferencesCaption, HangMitigatingCancellationToken); + + var activeWindowCaption = await TestServices.Shell.GetActiveWindowCaptionAsync(HangMitigatingCancellationToken); + Assert.Equal(expected: FindReferencesCaption, actual: activeWindowCaption); + + Assert.Collection( + results, + new Action[] + { + reference => + { + Assert.Equal(expected: "string local = \"1\";", actual: reference.TryGetValue(StandardTableKeyNames.Text, out string code) ? code : null); + Assert.Equal(expected: 5, actual: reference.TryGetValue(StandardTableKeyNames.Line, out int line) ? line : -1); + Assert.Equal(expected: 24, actual: reference.TryGetValue(StandardTableKeyNames.Column, out int column) ? column : -1); + } + }); + } + + [IdeFact] + public async Task VerifyWorkingFolder() + { + await SetUpEditorAsync(@"class EmptyContent {$$}", HangMitigatingCancellationToken); + + var visualStudioWorkspace = await TestServices.Shell.GetComponentModelServiceAsync(HangMitigatingCancellationToken); + var persistentStorageConfiguration = visualStudioWorkspace.Services.GetRequiredService(); + + // verify working folder has set + Assert.NotNull(persistentStorageConfiguration.TryGetStorageLocation(SolutionKey.ToSolutionKey(visualStudioWorkspace.CurrentSolution))); + + await TestServices.SolutionExplorer.CloseSolutionAsync(HangMitigatingCancellationToken); + + // because the solution cache directory is stored in the user temp folder, + // closing the solution has no effect on what is returned. + Assert.NotNull(persistentStorageConfiguration.TryGetStorageLocation(SolutionKey.ToSolutionKey(visualStudioWorkspace.CurrentSolution))); + } + + private async Task WaitForNavigateAsync(CancellationToken cancellationToken) + { + // Navigation operations handled by Roslyn are tracked by FeatureAttribute.FindReferences + await TestServices.Workspace.WaitForAsyncOperationsAsync(FeatureAttribute.FindReferences, cancellationToken); + + // Navigation operations handled by the editor are tracked within its own JoinableTaskFactory instance + await TestServices.Editor.WaitForEditorOperationsAsync(cancellationToken); + } + } +} diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/CriticalIdeTheoryAttribute.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CriticalIdeTheoryAttribute.cs new file mode 100644 index 0000000000000..88d824c8d74c5 --- /dev/null +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/CriticalIdeTheoryAttribute.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Xunit +{ + internal class CriticalIdeTheoryAttribute : IdeTheoryAttribute + { + [Obsolete("Critical tests cannot be skipped.", error: true)] + public new string Skip + { + get { return base.Skip; } + set { base.Skip = value; } + } + } +} diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/EditorInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/EditorInProcess.cs index e4fffaa3277e4..0b0059f274c2f 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/EditorInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/EditorInProcess.cs @@ -13,6 +13,7 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Input; +using System.Windows.Media; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Implementation.Suggestions; @@ -24,10 +25,13 @@ using Microsoft.VisualStudio.IntegrationTest.Utilities.Input; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion; +using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Classification; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.TextManager.Interop; +using Microsoft.VisualStudio.Threading; using Microsoft.VisualStudio.Utilities; using Roslyn.Utilities; using Roslyn.VisualStudio.IntegrationTests.InProcess; @@ -41,6 +45,19 @@ namespace Microsoft.VisualStudio.Extensibility.Testing { internal partial class EditorInProcess { + public async Task WaitForEditorOperationsAsync(CancellationToken cancellationToken) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + var shell = await GetRequiredGlobalServiceAsync(cancellationToken); + if (shell.IsPackageLoaded(DefGuidList.guidEditorPkg, out var editorPackage) == VSConstants.S_OK) + { + var asyncPackage = (AsyncPackage)editorPackage; + var collection = asyncPackage.GetPropertyValue("JoinableTaskCollection"); + await collection.JoinTillEmptyAsync(cancellationToken); + } + } + public async Task SetTextAsync(string text, CancellationToken cancellationToken) { await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); @@ -51,6 +68,49 @@ public async Task SetTextAsync(string text, CancellationToken cancellationToken) view.TextBuffer.Replace(replacementSpan, text); } + public async Task GetTextAsync(CancellationToken cancellationToken) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + var view = await TestServices.Editor.GetActiveTextViewAsync(cancellationToken); + var bufferPosition = view.Caret.Position.BufferPosition; + return bufferPosition.Snapshot.GetText(); + } + + public async Task GetCurrentLineTextAsync(CancellationToken cancellationToken) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + var view = await TestServices.Editor.GetActiveTextViewAsync(cancellationToken); + var bufferPosition = view.Caret.Position.BufferPosition; + var line = bufferPosition.GetContainingLine(); + return line.GetText(); + } + + public async Task GetLineTextBeforeCaretAsync(CancellationToken cancellationToken) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + var view = await TestServices.Editor.GetActiveTextViewAsync(cancellationToken); + var bufferPosition = view.Caret.Position.BufferPosition; + var line = bufferPosition.GetContainingLine(); + var lineText = line.GetText(); + var lineTextBeforeCaret = lineText[..(bufferPosition.Position - line.Start)]; + return lineTextBeforeCaret; + } + + public async Task GetLineTextAfterCaretAsync(CancellationToken cancellationToken) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + var view = await TestServices.Editor.GetActiveTextViewAsync(cancellationToken); + var bufferPosition = view.Caret.Position.BufferPosition; + var line = bufferPosition.GetContainingLine(); + var lineText = line.GetText(); + var lineTextAfterCaret = lineText[(bufferPosition.Position - line.Start)..]; + return lineTextAfterCaret; + } + public async Task MoveCaretAsync(int position, CancellationToken cancellationToken) { await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); @@ -65,6 +125,90 @@ public async Task MoveCaretAsync(int position, CancellationToken cancellationTok view.Caret.MoveTo(point); } + public async Task SelectTextInCurrentDocumentAsync(string text, CancellationToken cancellationToken) + { + await PlaceCaretAsync(text, charsOffset: -1, occurrence: 0, extendSelection: false, selectBlock: false, cancellationToken); + await PlaceCaretAsync(text, charsOffset: 0, occurrence: 0, extendSelection: true, selectBlock: false, cancellationToken); + } + + public async Task GetLightBulbPreviewClassificationsAsync(string menuText, CancellationToken cancellationToken) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + var view = await GetActiveTextViewAsync(cancellationToken); + var broker = await GetComponentModelServiceAsync(cancellationToken); + var classifierAggregatorService = await GetComponentModelServiceAsync(cancellationToken); + + await LightBulbHelper.WaitForLightBulbSessionAsync(TestServices, broker, view, cancellationToken).ConfigureAwait(true); + + var bufferType = view.TextBuffer.ContentType.DisplayName; + if (!broker.IsLightBulbSessionActive(view)) + { + throw new Exception($"No Active Smart Tags in View! Buffer content type='{bufferType}'"); + } + + var activeSession = broker.GetSession(view); + if (activeSession == null || !activeSession.IsExpanded) + { + throw new InvalidOperationException($"No expanded light bulb session found after View.ShowSmartTag. Buffer content type='{bufferType}'"); + } + + if (!string.IsNullOrEmpty(menuText)) + { + if (activeSession.TryGetSuggestedActionSets(out var actionSets) != QuerySuggestedActionCompletionStatus.Completed) + { + actionSets = Array.Empty(); + } + + var set = actionSets.SelectMany(s => s.Actions).FirstOrDefault(a => a.DisplayText == menuText); + if (set == null) + { + throw new InvalidOperationException( + $"ISuggestionAction '{menuText}' not found. Buffer content type='{bufferType}'"); + } + + IWpfTextView? preview = null; + var pane = await set.GetPreviewAsync(CancellationToken.None).ConfigureAwait(true); + if (pane is UserControl control) + { + var container = control.FindName("PreviewDockPanel") as DockPanel; + var host = FindDescendants(container).OfType().LastOrDefault(); + preview = host?.TextView; + } + + if (preview == null) + { + throw new InvalidOperationException(string.Format("Could not find light bulb preview. Buffer content type={0}", bufferType)); + } + + activeSession.Collapse(); + var classifier = classifierAggregatorService.GetClassifier(preview); + var classifiedSpans = classifier.GetClassificationSpans(new SnapshotSpan(preview.TextBuffer.CurrentSnapshot, 0, preview.TextBuffer.CurrentSnapshot.Length)); + return classifiedSpans.ToArray(); + } + + activeSession.Collapse(); + return Array.Empty(); + + static IEnumerable FindDescendants(DependencyObject? rootObject) + where T : DependencyObject + { + if (rootObject != null) + { + for (var i = 0; i < VisualTreeHelper.GetChildrenCount(rootObject); i++) + { + var child = VisualTreeHelper.GetChild(rootObject, i); + + if (child is not null and T) + yield return (T)child; + + foreach (var descendant in FindDescendants(child)) + yield return descendant; + } + } + } + } + public async Task ActivateAsync(CancellationToken cancellationToken) { await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); @@ -350,7 +494,7 @@ public async Task ShowLightBulbAsync(CancellationToken cancellationToken) var view = await GetActiveTextViewAsync(cancellationToken); var broker = await GetComponentModelServiceAsync(cancellationToken); - await LightBulbHelper.WaitForLightBulbSessionAsync(broker, view, cancellationToken); + await LightBulbHelper.WaitForLightBulbSessionAsync(TestServices, broker, view, cancellationToken); } public async Task InvokeCodeActionListAsync(CancellationToken cancellationToken) @@ -358,6 +502,13 @@ public async Task InvokeCodeActionListAsync(CancellationToken cancellationToken) await TestServices.Workspace.WaitForAsyncOperationsAsync(FeatureAttribute.SolutionCrawler, cancellationToken); await TestServices.Workspace.WaitForAsyncOperationsAsync(FeatureAttribute.DiagnosticService, cancellationToken); + await InvokeCodeActionListWithoutWaitingAsync(cancellationToken); + + await TestServices.Workspace.WaitForAsyncOperationsAsync(FeatureAttribute.LightBulb, cancellationToken); + } + + public async Task InvokeCodeActionListWithoutWaitingAsync(CancellationToken cancellationToken) + { if (Version.Parse("17.1.31916.450") > await TestServices.Shell.GetVersionAsync(cancellationToken)) { // Workaround for extremely unstable async lightbulb prior to: @@ -370,7 +521,6 @@ public async Task InvokeCodeActionListAsync(CancellationToken cancellationToken) } await ShowLightBulbAsync(cancellationToken); - await TestServices.Workspace.WaitForAsyncOperationsAsync(FeatureAttribute.LightBulb, cancellationToken); } public async Task IsLightBulbSessionExpandedAsync(CancellationToken cancellationToken) @@ -530,7 +680,7 @@ private async Task> GetLightBulbActionsAsync(ILigh throw new InvalidOperationException($"No expanded light bulb session found after View.ShowSmartTag. Buffer content type={bufferType}"); } - var actionSets = await LightBulbHelper.WaitForItemsAsync(broker, view, cancellationToken); + var actionSets = await LightBulbHelper.WaitForItemsAsync(TestServices, broker, view, cancellationToken); return await SelectActionsAsync(actionSets, cancellationToken); } diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/EditorVerifierInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/EditorVerifierInProcess.cs index 51da240d3f8ba..1039229c0f4f5 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/EditorVerifierInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/EditorVerifierInProcess.cs @@ -8,10 +8,14 @@ using System.Threading; using System.Threading.Tasks; using Microsoft; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.Extensibility.Testing; using Microsoft.VisualStudio.IntegrationTest.Utilities; +using Microsoft.VisualStudio.LanguageServices; +using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; @@ -31,8 +35,7 @@ public async Task CurrentLineTextAsync( } else { - var view = await TestServices.Editor.GetActiveTextViewAsync(cancellationToken); - var lineText = view.Caret.Position.BufferPosition.GetContainingLine().GetText(); + var lineText = await TestServices.Editor.GetCurrentLineTextAsync(cancellationToken); Assert.Equal(expectedText, lineText); } } @@ -52,12 +55,9 @@ private async Task CurrentLineTextAndAssertCaretPositionAsync( var expectedTextBeforeCaret = expectedText.Substring(0, expectedCaretIndex); var expectedTextAfterCaret = expectedText.Substring(expectedCaretMarkupEndIndex); - var view = await TestServices.Editor.GetActiveTextViewAsync(cancellationToken); - var bufferPosition = view.Caret.Position.BufferPosition; - var line = bufferPosition.GetContainingLine(); - var lineText = line.GetText(); - var lineTextBeforeCaret = lineText[..(bufferPosition.Position - line.Start)]; - var lineTextAfterCaret = lineText[(bufferPosition.Position - line.Start)..]; + var lineText = await TestServices.Editor.GetCurrentLineTextAsync(cancellationToken); + var lineTextBeforeCaret = await TestServices.Editor.GetLineTextBeforeCaretAsync(cancellationToken); + var lineTextAfterCaret = await TestServices.Editor.GetLineTextAfterCaretAsync(cancellationToken); Assert.Equal(expectedTextBeforeCaret, lineTextBeforeCaret); Assert.Equal(expectedTextAfterCaret, lineTextAfterCaret); @@ -145,6 +145,12 @@ public async Task CodeActionAsync( bool blockUntilComplete = true, CancellationToken cancellationToken = default) { + var events = new List(); + void WorkspaceChangedHandler(object sender, WorkspaceChangeEventArgs e) => events.Add(e); + + var workspace = await TestServices.Shell.GetComponentModelServiceAsync(cancellationToken); + using var workspaceEventRestorer = WithWorkspaceChangedHandler(workspace, WorkspaceChangedHandler); + await TestServices.Editor.ShowLightBulbAsync(cancellationToken); if (verifyNotShowing) @@ -178,12 +184,33 @@ public async Task CodeActionAsync( if (!RoslynString.IsNullOrEmpty(applyFix)) { + var codeActionLogger = new CodeActionLogger(); + using var loggerRestorer = WithLogger(AggregateLogger.AddOrReplace(codeActionLogger, Logger.GetLogger(), logger => logger is CodeActionLogger)); + var result = await TestServices.Editor.ApplyLightBulbActionAsync(applyFix, fixAllScope, blockUntilComplete, cancellationToken); if (blockUntilComplete) { // wait for action to complete - await TestServices.Workspace.WaitForAsyncOperationsAsync(FeatureAttribute.LightBulb, cancellationToken); + await TestServices.Workspace.WaitForAllAsyncOperationsAsync( + new[] + { + FeatureAttribute.Workspace, + FeatureAttribute.LightBulb, + }, + cancellationToken); + + if (codeActionLogger.Messages.Any()) + { + foreach (var e in events) + { + codeActionLogger.Messages.Add($"{e.OldSolution.WorkspaceVersion} to {e.NewSolution.WorkspaceVersion}: {e.Kind} {e.DocumentId}"); + } + } + + AssertEx.EqualOrDiff( + "", + string.Join(Environment.NewLine, codeActionLogger.Messages)); } return result; @@ -204,5 +231,77 @@ public async Task CaretPositionAsync(int expectedCaretPosition, CancellationToke { Assert.Equal(expectedCaretPosition, await TestServices.Editor.GetCaretPositionAsync(cancellationToken)); } + + private static WorkspaceEventRestorer WithWorkspaceChangedHandler(Workspace workspace, EventHandler eventHandler) + { + workspace.WorkspaceChanged += eventHandler; + return new WorkspaceEventRestorer(workspace, eventHandler); + } + + private static LoggerRestorer WithLogger(ILogger logger) + { + return new LoggerRestorer(Logger.SetLogger(logger)); + } + + private sealed class CodeActionLogger : ILogger + { + public List Messages { get; } = new(); + + public bool IsEnabled(FunctionId functionId) + { + return functionId == FunctionId.Workspace_ApplyChanges; + } + + public void Log(FunctionId functionId, LogMessage logMessage) + { + if (functionId != FunctionId.Workspace_ApplyChanges) + return; + + lock (Messages) + { + Messages.Add(logMessage.GetMessage()); + } + } + + public void LogBlockEnd(FunctionId functionId, LogMessage logMessage, int uniquePairId, int delta, CancellationToken cancellationToken) + { + } + + public void LogBlockStart(FunctionId functionId, LogMessage logMessage, int uniquePairId, CancellationToken cancellationToken) + { + } + } + + private readonly struct WorkspaceEventRestorer : IDisposable + { + private readonly Workspace _workspace; + private readonly EventHandler _eventHandler; + + public WorkspaceEventRestorer(Workspace workspace, EventHandler eventHandler) + { + _workspace = workspace; + _eventHandler = eventHandler; + } + + public void Dispose() + { + _workspace.WorkspaceChanged -= _eventHandler; + } + } + + private readonly struct LoggerRestorer : IDisposable + { + private readonly ILogger? _logger; + + public LoggerRestorer(ILogger? logger) + { + _logger = logger; + } + + public void Dispose() + { + Logger.SetLogger(_logger); + } + } } } diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ErrorListExtensions.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ErrorListExtensions.cs new file mode 100644 index 0000000000000..5d0ceeb1c3972 --- /dev/null +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ErrorListExtensions.cs @@ -0,0 +1,73 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Shell.TableManager; + +namespace Roslyn.VisualStudio.IntegrationTests.InProcess +{ + internal static class ErrorListExtensions + { + public static __VSERRORCATEGORY GetCategory(this ITableEntry tableEntry) + { + return tableEntry.GetValueOrDefault(StandardTableKeyNames.ErrorSeverity, (__VSERRORCATEGORY)(-1)); + } + + public static string GetBuildTool(this ITableEntry tableEntry) + { + return tableEntry.GetValueOrDefault(StandardTableKeyNames.BuildTool, ""); + } + + public static string? GetPath(this ITableEntry tableEntry) + { + return tableEntry.GetValueOrDefault(StandardTableKeyNames.Path, null); + } + + public static string? GetDocumentName(this ITableEntry tableEntry) + { + return tableEntry.GetValueOrDefault(StandardTableKeyNames.DocumentName, null); + } + + public static int? GetLine(this ITableEntry tableEntry) + { + return tableEntry.GetValueOrNull(StandardTableKeyNames.Line); + } + + public static int? GetColumn(this ITableEntry tableEntry) + { + return tableEntry.GetValueOrNull(StandardTableKeyNames.Column); + } + + public static string? GetErrorCode(this ITableEntry tableEntry) + { + return tableEntry.GetValueOrDefault(StandardTableKeyNames.ErrorCode, null); + } + + public static string? GetText(this ITableEntry tableEntry) + { + return tableEntry.GetValueOrDefault(StandardTableKeyNames.Text, null); + } + + private static T GetValueOrDefault(this ITableEntry tableEntry, string keyName, T defaultValue) + { + if (!tableEntry.TryGetValue(keyName, out T value)) + { + value = defaultValue; + } + + return value; + } + + private static T? GetValueOrNull(this ITableEntry tableEntry, string keyName) + where T : struct + { + if (!tableEntry.TryGetValue(keyName, out T value)) + { + return null; + } + + return value; + } + } +} diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ErrorListInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ErrorListInProcess.cs index f8920216dacbd..25af30b4cef9b 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ErrorListInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ErrorListInProcess.cs @@ -2,12 +2,101 @@ // The .NET Foundation 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.Threading; +using System.Threading.Tasks; using Microsoft.VisualStudio.Extensibility.Testing; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Shell.TableManager; +using Microsoft.VisualStudio.Threading; namespace Roslyn.VisualStudio.IntegrationTests.InProcess { [TestService] internal partial class ErrorListInProcess { + public Task ShowErrorListAsync(CancellationToken cancellationToken) + => ShowErrorListAsync(ErrorSource.Build | ErrorSource.Other, minimumSeverity: __VSERRORCATEGORY.EC_WARNING, cancellationToken); + + public Task ShowBuildErrorsAsync(CancellationToken cancellationToken) + => ShowErrorListAsync(ErrorSource.Build, minimumSeverity: __VSERRORCATEGORY.EC_WARNING, cancellationToken); + + public async Task ShowErrorListAsync(ErrorSource errorSource, __VSERRORCATEGORY minimumSeverity, CancellationToken cancellationToken) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + var errorList = await GetRequiredGlobalServiceAsync(cancellationToken); + ((IVsErrorList)errorList).BringToFront(); + errorList.AreBuildErrorSourceEntriesShown = errorSource.HasFlag(ErrorSource.Build); + errorList.AreOtherErrorSourceEntriesShown = errorSource.HasFlag(ErrorSource.Other); + errorList.AreErrorsShown = minimumSeverity >= __VSERRORCATEGORY.EC_ERROR; + errorList.AreWarningsShown = minimumSeverity >= __VSERRORCATEGORY.EC_WARNING; + errorList.AreMessagesShown = minimumSeverity >= __VSERRORCATEGORY.EC_MESSAGE; + } + + public Task> GetErrorsAsync(CancellationToken cancellationToken) + => GetErrorsAsync(ErrorSource.Build | ErrorSource.Other, minimumSeverity: __VSERRORCATEGORY.EC_WARNING, cancellationToken); + + public Task> GetBuildErrorsAsync(CancellationToken cancellationToken) + => GetErrorsAsync(ErrorSource.Build, minimumSeverity: __VSERRORCATEGORY.EC_WARNING, cancellationToken); + + public async Task> GetErrorsAsync(ErrorSource errorSource, __VSERRORCATEGORY minimumSeverity, CancellationToken cancellationToken) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + var errorItems = await GetErrorItemsAsync(cancellationToken); + var list = new List(); + + foreach (var item in errorItems) + { + if (item.GetCategory() > minimumSeverity) + { + continue; + } + + if (!item.TryGetValue(StandardTableKeyNames.ErrorSource, out ErrorSource itemErrorSource) + || !errorSource.HasFlag(itemErrorSource)) + { + continue; + } + + var source = item.GetBuildTool(); + var document = Path.GetFileName(item.GetPath() ?? item.GetDocumentName()) ?? ""; + var line = item.GetLine() ?? -1; + var column = item.GetColumn() ?? -1; + var errorCode = item.GetErrorCode() ?? ""; + var text = item.GetText() ?? ""; + var severity = item.GetCategory() switch + { + __VSERRORCATEGORY.EC_ERROR => "error", + __VSERRORCATEGORY.EC_WARNING => "warning", + __VSERRORCATEGORY.EC_MESSAGE => "info", + var unknown => unknown.ToString(), + }; + + var message = $"({source}) {document}({line + 1}, {column + 1}): {severity} {errorCode}: {text}"; + list.Add(message); + } + + return list + .OrderBy(x => x, StringComparer.OrdinalIgnoreCase) + .ThenBy(x => x, StringComparer.Ordinal) + .ToImmutableArray(); + } + + private async Task> GetErrorItemsAsync(CancellationToken cancellationToken) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + var errorList = await GetRequiredGlobalServiceAsync(cancellationToken); + var args = await errorList.TableControl.ForceUpdateAsync().WithCancellation(cancellationToken); + return args.AllEntries.ToImmutableArray(); + } } } diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/FindReferencesWindowInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/FindReferencesWindowInProcess.cs new file mode 100644 index 0000000000000..522016dc8fedb --- /dev/null +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/FindReferencesWindowInProcess.cs @@ -0,0 +1,76 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.VisualStudio.Extensibility.Testing; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Shell.TableControl; +using Microsoft.VisualStudio.Threading; + +namespace Roslyn.VisualStudio.IntegrationTests.InProcess +{ + [TestService] + internal partial class FindReferencesWindowInProcess + { + public async Task> GetContentsAsync(string windowCaption, CancellationToken cancellationToken) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + await TestServices.Workspace.WaitForAsyncOperationsAsync(FeatureAttribute.FindReferences, cancellationToken); + + // Find the tool window + var tableControl = await GetFindReferencesWindowAsync(windowCaption, cancellationToken); + + // Remove all grouping + var columnStates = tableControl.ColumnStates; + var newColumnsStates = new List(); + foreach (ColumnState2 state in columnStates) + { + var newState = new ColumnState2( + state.Name, + state.IsVisible, + state.Width, + state.SortPriority, + state.DescendingSort, + groupingPriority: 0); + newColumnsStates.Add(newState); + } + + tableControl.SetColumnStates(newColumnsStates); + + // Force a refresh, if necessary. This doesn't re-run the Find References or + // Find Implementations operation itself, it just forces the results to be + // realized in the table. + var forcedUpdateResult = await tableControl.ForceUpdateAsync().WithCancellation(cancellationToken); + + // Extract the basic text of the results. + return forcedUpdateResult.AllEntries.Cast().ToImmutableArray(); + } + + private async Task GetFindReferencesWindowAsync(string windowCaption, CancellationToken cancellationToken) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + var dte = await GetRequiredGlobalServiceAsync(cancellationToken); + + var toolWindow = dte.ToolWindows.GetToolWindow(windowCaption); + + // Dig through to get the Find References control. + var toolWindowType = toolWindow.GetType(); + var toolWindowControlField = toolWindowType.GetField("Control"); + var toolWindowControl = toolWindowControlField.GetValue(toolWindow); + + // Dig further to get the results table (as opposed to the toolbar). + var tableControlAndCommandTargetType = toolWindowControl.GetType(); + var tableControlField = tableControlAndCommandTargetType.GetField("TableControl"); + var tableControl = (IWpfTableControl2)tableControlField.GetValue(toolWindowControl); + return tableControl; + } + } +} diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/LightBulbHelper.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/LightBulbHelper.cs index e9dccfb8b3a47..3589828f89325 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/LightBulbHelper.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/LightBulbHelper.cs @@ -7,45 +7,40 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.VisualStudio.Extensibility.Testing; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Threading; namespace Roslyn.VisualStudio.IntegrationTests.InProcess { - public static class LightBulbHelper + internal static class LightBulbHelper { - public static async Task WaitForLightBulbSessionAsync(ILightBulbBroker broker, IWpfTextView view, CancellationToken cancellationToken) + public static async Task WaitForLightBulbSessionAsync(TestServices testServices, ILightBulbBroker broker, IWpfTextView view, CancellationToken cancellationToken) { - var startTime = DateTimeOffset.Now; - - var active = await Helper.RetryAsync(async cancellationToken => - { - if (broker.IsLightBulbSessionActive(view)) - { - return true; - } - - if (cancellationToken.IsCancellationRequested) - { - throw new InvalidOperationException("Expected a light bulb session to appear."); - } - - // checking whether there is any suggested action is async up to editor layer and our waiter doesn't track up to that point. - // so here, we have no other way than sleep (with timeout) to see LB is available. - await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); - - return broker.IsLightBulbSessionActive(view); - }, TimeSpan.FromMilliseconds(1), cancellationToken); - + await testServices.Editor.WaitForEditorOperationsAsync(cancellationToken); + var active = broker.IsLightBulbSessionActive(view); if (!active) return false; - await WaitForItemsAsync(broker, view, cancellationToken); + await WaitForItemsAsync(testServices, broker, view, cancellationToken); return true; } - public static async Task> WaitForItemsAsync(ILightBulbBroker broker, IWpfTextView view, CancellationToken cancellationToken) + public static async Task> WaitForItemsAsync(TestServices testServices, ILightBulbBroker broker, IWpfTextView view, CancellationToken cancellationToken) + { + while (true) + { + var items = await TryWaitForItemsAsync(testServices, broker, view, cancellationToken); + if (items is not null) + return items; + + // The session was dismissed unexpectedly. The editor might show it again. + await testServices.Editor.WaitForEditorOperationsAsync(cancellationToken); + } + } + + private static async Task?> TryWaitForItemsAsync(TestServices testServices, ILightBulbBroker broker, IWpfTextView view, CancellationToken cancellationToken) { var activeSession = broker.GetSession(view); if (activeSession == null) @@ -84,7 +79,20 @@ public static async Task> WaitForItemsAsync(ILig // that we hear about the results. asyncSession.PopulateWithData(overrideRequestedActionCategories: null, operationContext: null); - return await tcs.Task.WithCancellation(cancellationToken); + try + { + return await tcs.Task.WithCancellation(cancellationToken); + } + catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested) + { + if (Version.Parse("17.1.31928.29") >= await testServices.Shell.GetVersionAsync(cancellationToken)) + { + // Unexpected cancellation can occur when the editor dismisses the light bulb without request + return null; + } + + throw; + } } } } diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ShellInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ShellInProcess.cs index 6e20e5012972f..4d53d48932271 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ShellInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/ShellInProcess.cs @@ -2,9 +2,69 @@ // The .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.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.UnitTests; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Threading; +using IAsyncDisposable = System.IAsyncDisposable; + namespace Microsoft.VisualStudio.Extensibility.Testing { internal partial class ShellInProcess { + public async Task PauseFileChangesAsync(CancellationToken cancellationToken) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + var fileChangeService = await GetRequiredGlobalServiceAsync(cancellationToken); + Assumes.Present(fileChangeService); + + await fileChangeService.Pause(); + return new PauseFileChangesRestorer(fileChangeService); + } + + // This is based on WaitForQuiescenceAsync in the FileChangeService tests + public async Task WaitForFileChangeNotificationsAsync(CancellationToken cancellationToken) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + var fileChangeService = await GetRequiredGlobalServiceAsync(cancellationToken); + Assumes.Present(fileChangeService); + + var jobSynchronizer = fileChangeService.GetPropertyValue("JobSynchronizer"); + Assumes.Present(jobSynchronizer); + + var type = jobSynchronizer.GetType(); + var methodInfo = type.GetMethod("GetActiveSpawnedTasks", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + Assumes.Present(methodInfo); + + while (true) + { + var tasks = (Task[])methodInfo.Invoke(jobSynchronizer, null); + if (!tasks.Any()) + return; + + await Task.WhenAll(tasks); + } + } + + public readonly struct PauseFileChangesRestorer : IAsyncDisposable + { + private readonly IVsFileChangeEx3 _fileChangeService; + + public PauseFileChangesRestorer(IVsFileChangeEx3 fileChangeService) + { + _fileChangeService = fileChangeService; + } + + public async ValueTask DisposeAsync() + { + await _fileChangeService.Resume(); + } + } } } diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/SolutionExplorerInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/SolutionExplorerInProcess.cs index b258a3633e18e..38aaff963ecbf 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/SolutionExplorerInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/SolutionExplorerInProcess.cs @@ -318,6 +318,28 @@ public async Task AddFileAsync(string projectName, string fileName, string? cont } } + public async Task SetFileContentsAsync(string projectName, string relativeFilePath, string content, CancellationToken cancellationToken) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + var project = await GetProjectAsync(projectName, cancellationToken); + var projectPath = Path.GetDirectoryName(project.FullName); + var filePath = Path.Combine(projectPath, relativeFilePath); + + File.WriteAllText(filePath, content); + } + + public async Task GetFileContentsAsync(string projectName, string relativeFilePath, CancellationToken cancellationToken) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + var project = await GetProjectAsync(projectName, cancellationToken); + var projectPath = Path.GetDirectoryName(project.FullName); + var filePath = Path.Combine(projectPath, relativeFilePath); + + return File.ReadAllText(filePath); + } + private static string ConvertLanguageName(string languageName) { return languageName switch diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/SolutionVerifierInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/SolutionVerifierInProcess.cs index c57af108f6ef0..4c1d56bcaaa62 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/SolutionVerifierInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/SolutionVerifierInProcess.cs @@ -24,5 +24,11 @@ public async Task ProjectReferencePresent(string projectName, string referencedP var projectReferences = await TestServices.SolutionExplorer.GetProjectReferencesAsync(projectName, cancellationToken); Assert.Contains(referencedProjectName, projectReferences); } + + public async Task FileContentsAsync(string projectName, string fileName, string expectedContents, CancellationToken cancellationToken) + { + var actualContents = await TestServices.SolutionExplorer.GetFileContentsAsync(projectName, fileName, cancellationToken); + Assert.Equal(expectedContents, actualContents); + } } } diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/StateResetInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/StateResetInProcess.cs index 57d5ad9e7e93f..a86eba6735653 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/StateResetInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/StateResetInProcess.cs @@ -2,12 +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. +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Options; using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio; using Microsoft.VisualStudio.Extensibility.Testing; +using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text.Editor; namespace Roslyn.VisualStudio.IntegrationTests.InProcess @@ -18,7 +21,13 @@ internal partial class StateResetInProcess public async Task ResetGlobalOptionsAsync(CancellationToken cancellationToken) { var globalOptions = await GetComponentModelServiceAsync(cancellationToken); - globalOptions.SetGlobalOption(new OptionKey(NavigationBarViewOptions.ShowNavigationBar, LanguageNames.CSharp), true); + ResetPerLanguageOption(globalOptions, NavigationBarViewOptions.ShowNavigationBar); + + static void ResetPerLanguageOption(IGlobalOptionService globalOptions, PerLanguageOption option) + { + globalOptions.SetGlobalOption(new OptionKey(option, LanguageNames.CSharp), option.DefaultValue); + globalOptions.SetGlobalOption(new OptionKey(option, LanguageNames.VisualBasic), option.DefaultValue); + } } public async Task ResetHostSettingsAsync(CancellationToken cancellationToken) @@ -36,6 +45,16 @@ public async Task ResetHostSettingsAsync(CancellationToken cancellationToken) var latencyGuardOptionKey = new EditorOptionKey("EnableTypingLatencyGuard"); options.SetOptionValue(latencyGuardOptionKey, false); + + // Close all Find References windows + await foreach (var window in TestServices.Shell.EnumerateWindowsAsync(__WindowFrameTypeFlags.WINDOWFRAMETYPE_Tool, cancellationToken).WithCancellation(cancellationToken)) + { + ErrorHandler.ThrowOnFailure(window.GetProperty((int)__VSFPROPID.VSFPROPID_Caption, out var captionObj)); + if (Regex.IsMatch($"{captionObj}", "^(?:'.*' references|Find All References(?: \\d)?)$")) + { + window.CloseFrame((uint)__FRAMECLOSE.FRAMECLOSE_NoSave); + } + } } } } diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/TelemetryInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/TelemetryInProcess.cs new file mode 100644 index 0000000000000..34a1a019c322b --- /dev/null +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/TelemetryInProcess.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.Threading; +using System.Threading.Tasks; +using Microsoft.VisualStudio.Extensibility.Testing; +using Microsoft.VisualStudio.Telemetry; +using Microsoft.VisualStudio.Threading; +using Xunit; +using IAsyncDisposable = System.IAsyncDisposable; + +namespace Roslyn.VisualStudio.IntegrationTests.InProcess +{ + [TestService] + internal partial class TelemetryInProcess + { + internal async Task EnableTestTelemetryChannelAsync(CancellationToken cancellationToken) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + TelemetryService.DetachTestChannel(LoggerTestChannel.Instance); + + LoggerTestChannel.Instance.Clear(); + + TelemetryService.AttachTestChannel(LoggerTestChannel.Instance); + + return new TelemetryVerifier(TestServices); + } + + internal async Task DisableTestTelemetryChannelAsync(CancellationToken cancellationToken) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + TelemetryService.DetachTestChannel(LoggerTestChannel.Instance); + + LoggerTestChannel.Instance.Clear(); + } + + public async Task TryWaitForTelemetryEventsAsync(string[] names, CancellationToken cancellationToken) + => await LoggerTestChannel.Instance.TryWaitForEventsAsync(names, cancellationToken); + + public class TelemetryVerifier : IAsyncDisposable + { + internal TestServices _testServices; + + public TelemetryVerifier(TestServices testServices) + { + _testServices = testServices; + } + + public async ValueTask DisposeAsync() + => await _testServices.Telemetry.DisableTestTelemetryChannelAsync(CancellationToken.None); + + /// + /// Asserts that a telemetry event of the given name was fired. Does not + /// do any additional validation (of performance numbers, etc). + /// + /// + public async Task VerifyFiredAsync(string[] expectedEventNames, CancellationToken cancellationToken) + { + var telemetryEnabled = await _testServices.Telemetry.TryWaitForTelemetryEventsAsync(expectedEventNames, cancellationToken); + if (string.Equals(Environment.GetEnvironmentVariable("ROSLYN_TEST_CI"), "true", StringComparison.OrdinalIgnoreCase)) + { + // Telemetry verification is optional for developer machines, but required for CI. + Assert.True(telemetryEnabled); + } + } + } + + private sealed class LoggerTestChannel : ITelemetryTestChannel + { + public static readonly LoggerTestChannel Instance = new(); + + private AsyncQueue _eventsQueue = new(); + + /// + /// Waits for one or more events with the specified names + /// + /// + public async Task TryWaitForEventsAsync(string[] events, CancellationToken cancellationToken) + { + if (!TelemetryService.DefaultSession.IsOptedIn) + return false; + + var set = new HashSet(events); + while (set.Count > 0) + { + var result = await _eventsQueue.DequeueAsync(cancellationToken); + set.Remove(result.Name); + } + + return true; + } + + /// + /// Clear current queue. + /// + public void Clear() + { + _eventsQueue.Complete(); + _eventsQueue = new AsyncQueue(); + } + + /// + /// Process incoming events. + /// + /// + /// + void ITelemetryTestChannel.OnPostEvent(object sender, TelemetryTestChannelEventArgs e) + { + _eventsQueue.Enqueue(e.Event); + } + } + } +} diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/WorkspaceInProcess.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/WorkspaceInProcess.cs index a33d4a7d39c4b..9bfa6f7cc2a11 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/WorkspaceInProcess.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/InProcess/WorkspaceInProcess.cs @@ -6,7 +6,9 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Editor.Shared.Options; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.TestHooks; +using Microsoft.VisualStudio.LanguageServices; using Microsoft.VisualStudio.Threading; namespace Microsoft.VisualStudio.Extensibility.Testing @@ -53,5 +55,19 @@ public async Task WaitForAsyncOperationsAsync(string featuresToWaitFor, bool wai var featureWaiter = listenerProvider.GetWaiter(featuresToWaitFor); await featureWaiter.ExpeditedWaitAsync().WithCancellation(cancellationToken); } + + public async Task WaitForAllAsyncOperationsAsync(string[] featureNames, CancellationToken cancellationToken) + { + if (featureNames.Contains(FeatureAttribute.Workspace)) + { + await WaitForProjectSystemAsync(cancellationToken); + await TestServices.Shell.WaitForFileChangeNotificationsAsync(cancellationToken); + await TestServices.Editor.WaitForEditorOperationsAsync(cancellationToken); + } + + var listenerProvider = await GetComponentModelServiceAsync(cancellationToken); + var workspace = await GetComponentModelServiceAsync(cancellationToken); + await listenerProvider.WaitAllAsync(workspace, featureNames).WithCancellation(cancellationToken); + } } } diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicAddMissingReference.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicAddMissingReference.cs index ffbd1e6bbce4a..b8276052ca876 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicAddMissingReference.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicAddMissingReference.cs @@ -8,11 +8,11 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.IntegrationTest.Utilities; using Roslyn.VisualStudio.IntegrationTests; -using Roslyn.VisualStudio.IntegrationTests.InProcess; using Xunit; namespace Roslyn.VisualStudio.NewIntegrationTests.VisualBasic { + [Trait(Traits.Feature, Traits.Features.AddMissingReference)] public class BasicAddMissingReference : AbstractEditorTest { private const string FileInLibraryProject1 = @"Public Class Class1 @@ -144,7 +144,26 @@ await TestServices.SolutionExplorer.CreateSolutionAsync("ReferenceErrors", solut ""), HangMitigatingCancellationToken); } - [IdeFact, Trait(Traits.Feature, Traits.Features.AddMissingReference)] + [IdeFact] + public async Task VerifyAvailableCodeActions() + { + var consoleProject = ConsoleProjectName; + await TestServices.SolutionExplorer.OpenFileAsync(consoleProject, "Module1.vb", HangMitigatingCancellationToken); + await TestServices.Editor.PlaceCaretAsync("y.goo", charsOffset: 1, HangMitigatingCancellationToken); + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync("Add reference to 'System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.", applyFix: false, cancellationToken: HangMitigatingCancellationToken); + await TestServices.Editor.PlaceCaretAsync("x.goo", charsOffset: 1, HangMitigatingCancellationToken); + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync("Add reference to 'System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.", applyFix: false, cancellationToken: HangMitigatingCancellationToken); + await TestServices.Editor.PlaceCaretAsync("z.DialogResult", charsOffset: 1, HangMitigatingCancellationToken); + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync("Add reference to 'System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.", applyFix: false, cancellationToken: HangMitigatingCancellationToken); + await TestServices.Editor.PlaceCaretAsync("a.bar", charsOffset: 1, HangMitigatingCancellationToken); + await TestServices.Editor.InvokeCodeActionListAsync(HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CodeActionAsync("Add project reference to 'ClassLibrary3'.", applyFix: false, cancellationToken: HangMitigatingCancellationToken); + } + + [IdeFact] public async Task InvokeSomeFixesInVisualBasicThenVerifyReferences() { await TestServices.SolutionExplorer.OpenFileAsync(ConsoleProjectName, "Module1.vb", HangMitigatingCancellationToken); diff --git a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicNavigationBar.cs b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicNavigationBar.cs index 970818476badd..578f78b1548bb 100644 --- a/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicNavigationBar.cs +++ b/src/VisualStudio/IntegrationTest/New.IntegrationTests/VisualBasic/BasicNavigationBar.cs @@ -5,12 +5,16 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.Editor.Options; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.VisualStudio.Text.Operations; using Roslyn.VisualStudio.IntegrationTests; using Xunit; namespace Roslyn.VisualStudio.NewIntegrationTests.VisualBasic { + [Trait(Traits.Feature, Traits.Features.NavigationBar)] public class BasicNavigationBar : AbstractEditorTest { private const string TestSource = @" @@ -33,7 +37,51 @@ public BasicNavigationBar() protected override string LanguageName => LanguageNames.VisualBasic; [IdeFact] - [Trait(Traits.Feature, Traits.Features.NavigationBar)] + public async Task VerifyNavBar() + { + await SetUpEditorAsync(TestSource, HangMitigatingCancellationToken); + + await TestServices.Editor.PlaceCaretAsync("Goo", charsOffset: 1, HangMitigatingCancellationToken); + + Assert.Equal("C", await TestServices.Editor.GetNavigationBarSelectionAsync(NavigationBarDropdownKind.Type, HangMitigatingCancellationToken)); + Assert.Equal("Goo", await TestServices.Editor.GetNavigationBarSelectionAsync(NavigationBarDropdownKind.Member, HangMitigatingCancellationToken)); + + await TestServices.Editor.ExpandNavigationBarAsync(NavigationBarDropdownKind.Type, HangMitigatingCancellationToken); + var expectedItems = new[] + { + "C", + "Domain", + "S", + }; + + Assert.Equal(expectedItems, await TestServices.Editor.GetNavigationBarItemsAsync(NavigationBarDropdownKind.Type, HangMitigatingCancellationToken)); + + await TestServices.Editor.SelectNavigationBarItemAsync(NavigationBarDropdownKind.Type, "S", HangMitigatingCancellationToken); + + await TestServices.EditorVerifier.CaretPositionAsync(112, HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CurrentLineTextAsync("Structure $$S", assertCaretPosition: true); + + var view = await TestServices.Editor.GetActiveTextViewAsync(HangMitigatingCancellationToken); + var editorOperationsFactory = await TestServices.Shell.GetComponentModelServiceAsync(HangMitigatingCancellationToken); + var editorOperations = editorOperationsFactory.GetEditorOperations(view); + editorOperations.MoveLineDown(extendSelection: false); + + Assert.Equal("A", await TestServices.Editor.GetNavigationBarSelectionAsync(NavigationBarDropdownKind.Member, HangMitigatingCancellationToken)); + + await TestServices.Editor.ExpandNavigationBarAsync(NavigationBarDropdownKind.Member, HangMitigatingCancellationToken); + expectedItems = new[] + { + "A", + "B", + }; + + Assert.Equal(expectedItems, await TestServices.Editor.GetNavigationBarItemsAsync(NavigationBarDropdownKind.Member, HangMitigatingCancellationToken)); + await TestServices.Editor.SelectNavigationBarItemAsync(NavigationBarDropdownKind.Member, "B", HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CaretPositionAsync(169, HangMitigatingCancellationToken); + await TestServices.EditorVerifier.CurrentLineTextAsync(" Public Property $$B As Integer", assertCaretPosition: true, HangMitigatingCancellationToken); + } + + [IdeFact] public async Task CodeSpit() { await SetUpEditorAsync(TestSource, HangMitigatingCancellationToken); @@ -50,5 +98,17 @@ Public Sub New() await TestServices.EditorVerifier.CaretPositionAsync(78, HangMitigatingCancellationToken); // Caret is between New() and End Sub() in virtual whitespace await TestServices.EditorVerifier.CurrentLineTextAsync("$$", assertCaretPosition: true, HangMitigatingCancellationToken); } + + [IdeFact] + public async Task VerifyOption() + { + var globalOptions = await TestServices.Shell.GetComponentModelServiceAsync(HangMitigatingCancellationToken); + + globalOptions.SetGlobalOption(new OptionKey(NavigationBarViewOptions.ShowNavigationBar, LanguageNames.VisualBasic), false); + Assert.False(await TestServices.Editor.IsNavigationBarEnabledAsync(HangMitigatingCancellationToken)); + + globalOptions.SetGlobalOption(new OptionKey(NavigationBarViewOptions.ShowNavigationBar, LanguageNames.VisualBasic), true); + Assert.True(await TestServices.Editor.IsNavigationBarEnabledAsync(HangMitigatingCancellationToken)); + } } } diff --git a/src/VisualStudio/IntegrationTest/TestSetup/IntegrationTestServiceCommands.cs b/src/VisualStudio/IntegrationTest/TestSetup/IntegrationTestServiceCommands.cs index ca2f91d3d07b2..6acaeff99d5a8 100644 --- a/src/VisualStudio/IntegrationTest/TestSetup/IntegrationTestServiceCommands.cs +++ b/src/VisualStudio/IntegrationTest/TestSetup/IntegrationTestServiceCommands.cs @@ -149,7 +149,7 @@ private void StopServiceCallback(object sender, EventArgs e) } } - private void SwapAvailableCommands(MenuCommand commandToDisable, MenuCommand commandToEnable) + private static void SwapAvailableCommands(MenuCommand commandToDisable, MenuCommand commandToEnable) { commandToDisable.Enabled = false; commandToDisable.Visible = false; diff --git a/src/VisualStudio/IntegrationTest/TestSetup/Microsoft.VisualStudio.IntegrationTest.Setup.csproj b/src/VisualStudio/IntegrationTest/TestSetup/Microsoft.VisualStudio.IntegrationTest.Setup.csproj index 66ea327988a75..034e5f0785391 100644 --- a/src/VisualStudio/IntegrationTest/TestSetup/Microsoft.VisualStudio.IntegrationTest.Setup.csproj +++ b/src/VisualStudio/IntegrationTest/TestSetup/Microsoft.VisualStudio.IntegrationTest.Setup.csproj @@ -53,12 +53,6 @@ - - Diagnostics - BuiltProjectOutputGroup%3bBuiltProjectOutputGroupDependencies%3bGetCopyToOutputDirectoryItems%3bSatelliteDllsProjectOutputGroup%3b - DebugSymbolsProjectOutputGroup%3b - CodeBase - Workspaces False diff --git a/src/VisualStudio/IntegrationTest/TestSetup/source.extension.vsixmanifest b/src/VisualStudio/IntegrationTest/TestSetup/source.extension.vsixmanifest index 2a739f85960b2..05857e7967b19 100644 --- a/src/VisualStudio/IntegrationTest/TestSetup/source.extension.vsixmanifest +++ b/src/VisualStudio/IntegrationTest/TestSetup/source.extension.vsixmanifest @@ -22,7 +22,6 @@ - diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/CodeDefinitionWindow_InProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/CodeDefinitionWindow_InProc.cs index 393b5c0ed818a..07c42671c8d36 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/CodeDefinitionWindow_InProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/CodeDefinitionWindow_InProc.cs @@ -28,7 +28,7 @@ private CodeDefinitionWindow_InProc() public static CodeDefinitionWindow_InProc Create() => new CodeDefinitionWindow_InProc(); - private IWpfTextView GetCodeDefinitionWpfTextView() + private static IWpfTextView GetCodeDefinitionWpfTextView() { var shell = GetGlobalService(); var windowGuid = Guid.Parse(ToolWindowGuids80.CodedefinitionWindow); @@ -58,7 +58,7 @@ public void Show() /// Waits for all async processing to complete, including the async processing in the /// code definition window itself. /// - private void WaitUntilProcessingComplete() + private static void WaitUntilProcessingComplete() { GetWaitingService().WaitForAsyncOperations(FeatureAttribute.CodeDefinitionWindow); diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/Debugger_InProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/Debugger_InProc.cs index 27c4eb4f87dca..b8c197ec55bd4 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/Debugger_InProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/Debugger_InProc.cs @@ -43,7 +43,7 @@ public void SetBreakPoint(string fileName, int lineNumber, int columnIndex) public void Go(bool waitForBreakMode) => _debugger.Go(waitForBreakMode); - public void StepOver(bool waitForBreakOrEnd) => this.WaitForRaiseDebuggerDteCommand(() => _debugger.StepOver(waitForBreakOrEnd)); + public void StepOver(bool waitForBreakOrEnd) => WaitForRaiseDebuggerDteCommand(() => _debugger.StepOver(waitForBreakOrEnd)); public void Stop(bool waitForDesignMode) => _debugger.Stop(WaitForDesignMode: waitForDesignMode); @@ -57,7 +57,7 @@ public void SetBreakPoint(string fileName, int lineNumber, int columnIndex) /// Executes the specified action delegate and retries if Operation Not Supported is thrown. /// /// Action delegate to exectute. - private void WaitForRaiseDebuggerDteCommand(Action action) + private static void WaitForRaiseDebuggerDteCommand(Action action) { var actionSucceeded = false; diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/Editor_InProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/Editor_InProc.cs index faca11b3b878f..a921e07bf4f40 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/Editor_InProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/Editor_InProc.cs @@ -799,6 +799,9 @@ public void GoToDefinition() public void GoToImplementation() => ExecuteCommand(WellKnownCommandNames.Edit_GoToImplementation); + public void GoToBase() + => ExecuteCommand(WellKnownCommandNames.Edit_GoToBase); + /// /// Gets the spans where a particular tag appears in the active text view. /// diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/ErrorList_InProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/ErrorList_InProc.cs index babab50dd447b..2fd519c8f91ad 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/ErrorList_InProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/ErrorList_InProc.cs @@ -100,7 +100,7 @@ public ErrorListItem[] GetErrorListContents(__VSERRORCATEGORY minimumSeverity = } } - private IVsEnumTaskItems GetErrorItems() + private static IVsEnumTaskItems GetErrorItems() { return InvokeOnUIThread(cancellationToken => { diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/InProcComponent.cs b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/InProcComponent.cs index 6b816741b1297..e0322a13457d1 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/InProcComponent.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/InProcComponent.cs @@ -7,6 +7,7 @@ using System.Windows; using System.Windows.Threading; using EnvDTE; +using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; @@ -84,8 +85,8 @@ protected static TService GetComponentModelService() where TService : class => InvokeOnUIThread(cancellationToken => GetComponentModel().GetService()); - protected static TestingOnly_WaitingService GetWaitingService() - => GetComponentModel().DefaultExportProvider.GetExport().Value; + protected static TestWaitingService GetWaitingService() + => new(GetComponentModel().DefaultExportProvider.GetExport().Value); protected static DTE GetDTE() => GetGlobalService(); diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/InteractiveWindow_InProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/InteractiveWindow_InProc.cs index 4fda3ae839c3b..4678e1e2e6743 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/InteractiveWindow_InProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/InteractiveWindow_InProc.cs @@ -235,7 +235,7 @@ public void WaitForLastReplOutputContains(string outputText) public void WaitForLastReplInputContains(string outputText) => WaitForPredicate(GetLastReplInput, outputText, s_contains, "contain"); - private void WaitForPredicate(Func getValue, string expectedValue, Func valueComparer, string verb) + private static void WaitForPredicate(Func getValue, string expectedValue, Func valueComparer, string verb) { var beginTime = DateTime.UtcNow; diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/LocalsWindow_InProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/LocalsWindow_InProc.cs index 142c00d85f151..854e159300c95 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/LocalsWindow_InProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/LocalsWindow_InProc.cs @@ -53,7 +53,7 @@ public Common.Expression GetEntry(params string[] entryNames) throw new Exception($"\nCould not find the local named {localHierarchicalName}.\nAll available locals are: \n{allLocalsString}"); } - private bool TryGetEntryInternal(string entryName, EnvDTE.Expressions expressions, out EnvDTE.Expression expression) + private static bool TryGetEntryInternal(string entryName, EnvDTE.Expressions expressions, out EnvDTE.Expression expression) { expression = expressions.Cast().FirstOrDefault(e => e.Name == entryName); if (expression != null) diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/PickMembersDialog_InProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/PickMembersDialog_InProc.cs index a1b19c0d4997e..c16eebae2e8b1 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/PickMembersDialog_InProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/PickMembersDialog_InProc.cs @@ -103,19 +103,19 @@ public void ClickDown() } } - private async Task GetDialogAsync(CancellationToken cancellationToken) + private static async Task GetDialogAsync(CancellationToken cancellationToken) { await JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, cancellationToken); return Application.Current.Windows.OfType().Single(); } - private async Task TryGetDialogAsync(CancellationToken cancellationToken) + private static async Task TryGetDialogAsync(CancellationToken cancellationToken) { await JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, cancellationToken); return Application.Current.Windows.OfType().SingleOrDefault(); } - private async Task ClickAsync(Func buttonSelector, CancellationToken cancellationToken) + private static async Task ClickAsync(Func buttonSelector, CancellationToken cancellationToken) { await JoinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true, cancellationToken); var dialog = await GetDialogAsync(cancellationToken); diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/SolutionExplorer_InProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/SolutionExplorer_InProc.cs index d164f8733fd14..826c8e092255d 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/SolutionExplorer_InProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/SolutionExplorer_InProc.cs @@ -506,7 +506,7 @@ private void CloseSolution() } } - var waitingService = GetComponentModel().DefaultExportProvider.GetExportedValue(); + var waitingService = new TestWaitingService(GetComponentModel().DefaultExportProvider.GetExportedValue()); waitingService.WaitForAsyncOperations(FeatureAttribute.Workspace, waitForWorkspaceFirst: true); } @@ -746,7 +746,7 @@ public void ClearBuildOutputWindowPane() buildOutputWindowPane.Clear(); } - private EnvDTE.OutputWindowPane GetBuildOutputWindowPane() + private static EnvDTE.OutputWindowPane GetBuildOutputWindowPane() { var dte = (DTE2)GetDTE(); var outputWindow = dte.ToolWindows.OutputWindow; diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/StartPage_InProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/StartPage_InProc.cs index 981d2e8b9f738..7d077e0e92540 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/StartPage_InProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/StartPage_InProc.cs @@ -68,7 +68,7 @@ public bool CloseWindow() }); } - private EnvDTE.Property GetProperty() + private static EnvDTE.Property GetProperty() => GetDTE().get_Properties("Environment", "Startup").Item("OnStartUp"); } } diff --git a/src/Test/Diagnostics/TestingOnly_WaitingService.cs b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/TestWaitingService.cs similarity index 90% rename from src/Test/Diagnostics/TestingOnly_WaitingService.cs rename to src/VisualStudio/IntegrationTest/TestUtilities/InProcess/TestWaitingService.cs index 4e70d67f2ebd0..b1643517c00a5 100644 --- a/src/Test/Diagnostics/TestingOnly_WaitingService.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/TestWaitingService.cs @@ -3,27 +3,22 @@ // See the LICENSE file in the project root for more information. using System; -using System.Composition; using System.Threading; using System.Threading.Tasks; using System.Windows.Threading; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.TestHooks; using Roslyn.Utilities; namespace Roslyn.Hosting.Diagnostics.Waiters { - [Export, Shared] - internal class TestingOnly_WaitingService + internal sealed class TestWaitingService { private readonly AsynchronousOperationListenerProvider _provider; - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public TestingOnly_WaitingService(IAsynchronousOperationListenerProvider provider) + public TestWaitingService(AsynchronousOperationListenerProvider provider) { - _provider = (AsynchronousOperationListenerProvider)provider; + _provider = provider; } public void WaitForAsyncOperations(string featureName, bool waitForWorkspaceFirst = true) diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/VisualStudioWorkspace_InProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/VisualStudioWorkspace_InProc.cs index 745766fdf8cc4..e7276d7c72659 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/VisualStudioWorkspace_InProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/VisualStudioWorkspace_InProc.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Immutable; using System.ComponentModel; using System.Linq; using System.Runtime.InteropServices; @@ -48,7 +49,7 @@ public void SetOptionInfer(string projectName, bool value) project.Properties.Item("OptionInfer").Value = convertedValue; }); - private EnvDTE.Project GetProject(string nameOrFileName) + private static EnvDTE.Project GetProject(string nameOrFileName) => GetDTE().Solution.Projects.OfType().First(p => string.Compare(p.FileName, nameOrFileName, StringComparison.OrdinalIgnoreCase) == 0 || string.Compare(p.Name, nameOrFileName, StringComparison.OrdinalIgnoreCase) == 0); @@ -89,6 +90,16 @@ public void SetOption(string optionName, string feature, object value) SetOption(optionKey, result); } + public object? GetGlobalOption(WellKnownGlobalOption option, string? language) + { + object? result = null; + InvokeOnUIThread(_ => result = _globalOptions.GetOption(option.GetKey(language))); + return result; + } + + public void SetGlobalOption(WellKnownGlobalOption option, string? language, object? value) + => InvokeOnUIThread(_ => _globalOptions.SetGlobalOption(option.GetKey(language), value)); + private static object GetValue(object value, IOption option) { object result; diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/Microsoft.VisualStudio.IntegrationTest.Utilities.csproj b/src/VisualStudio/IntegrationTest/TestUtilities/Microsoft.VisualStudio.IntegrationTest.Utilities.csproj index 4f723aaa517af..1cd0d5246af42 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/Microsoft.VisualStudio.IntegrationTest.Utilities.csproj +++ b/src/VisualStudio/IntegrationTest/TestUtilities/Microsoft.VisualStudio.IntegrationTest.Utilities.csproj @@ -58,7 +58,6 @@ - diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/Editor_OutOfProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/Editor_OutOfProc.cs index e42572d998e06..8d84cb826e7a7 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/Editor_OutOfProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/Editor_OutOfProc.cs @@ -359,7 +359,7 @@ public TextSpan[] GetOutliningSpans() return Deserialize(_editorInProc.GetOutliningSpans()); } - private TextSpan[] Deserialize(string[] v) + private static TextSpan[] Deserialize(string[] v) { // returned tag looks something like 'text'[12-13] return v.Select(tag => @@ -387,6 +387,14 @@ public void GoToImplementation(string expectedWindowName) _editorInProc.WaitForActiveWindow(expectedWindowName); } + public void GoToBase(string expectedWindowName) + { + _instance.Workspace.WaitForAsyncOperations(Helper.HangMitigatingTimeout, FeatureAttribute.Workspace); + _editorInProc.GoToBase(); + _instance.Workspace.WaitForAsyncOperations(Helper.HangMitigatingTimeout, FeatureAttribute.GoToBase); + _editorInProc.WaitForActiveWindow(expectedWindowName); + } + public void SendExplicitFocus() => _editorInProc.SendExplicitFocus(); diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/VisualStudioWorkspace_OutOfProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/VisualStudioWorkspace_OutOfProc.cs index 6d7a73c7eafbc..5411f6e5cb2b4 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/VisualStudioWorkspace_OutOfProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/OutOfProcess/VisualStudioWorkspace_OutOfProc.cs @@ -6,6 +6,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.VisualStudio.IntegrationTest.Utilities.InProcess; @@ -59,17 +60,8 @@ public void CleanUpWaitingService() public void SetImportCompletionOption(bool value) { - SetPerLanguageOption( - optionName: "ShowItemsFromUnimportedNamespaces", - feature: "CompletionOptions", - language: LanguageNames.CSharp, - value: value); - - SetPerLanguageOption( - optionName: "ShowItemsFromUnimportedNamespaces", - feature: "CompletionOptions", - language: LanguageNames.VisualBasic, - value: value); + SetGlobalOption(WellKnownGlobalOption.CompletionOptions_ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, value); + SetGlobalOption(WellKnownGlobalOption.CompletionOptions_ShowItemsFromUnimportedNamespaces, LanguageNames.VisualBasic, value); } public void SetEnableDecompilationOption(bool value) @@ -79,27 +71,12 @@ public void SetEnableDecompilationOption(bool value) public void SetArgumentCompletionSnippetsOption(bool value) { - SetPerLanguageOption( - optionName: CompletionViewOptions.EnableArgumentCompletionSnippets.Name, - feature: CompletionViewOptions.EnableArgumentCompletionSnippets.Feature, - language: LanguageNames.CSharp, - value: value); - - SetPerLanguageOption( - optionName: CompletionViewOptions.EnableArgumentCompletionSnippets.Name, - feature: CompletionViewOptions.EnableArgumentCompletionSnippets.Feature, - language: LanguageNames.VisualBasic, - value: value); + SetGlobalOption(WellKnownGlobalOption.CompletionViewOptions_EnableArgumentCompletionSnippets, LanguageNames.CSharp, value); + SetGlobalOption(WellKnownGlobalOption.CompletionViewOptions_EnableArgumentCompletionSnippets, LanguageNames.VisualBasic, value); } public void SetTriggerCompletionInArgumentLists(bool value) - { - SetPerLanguageOption( - optionName: CompletionOptions.Metadata.TriggerInArgumentLists.Name, - feature: CompletionOptions.Metadata.TriggerInArgumentLists.Feature, - language: LanguageNames.CSharp, - value: value); - } + => SetGlobalOption(WellKnownGlobalOption.CompletionOptions_TriggerInArgumentLists, LanguageNames.CSharp, value); public void SetFullSolutionAnalysis(bool value) { @@ -130,6 +107,12 @@ public void SetEnableOpeningSourceGeneratedFilesInWorkspaceExperiment(bool value public void SetFeatureOption(string feature, string optionName, string language, string? valueString) => _inProc.SetFeatureOption(feature, optionName, language, valueString); + public object? GetGlobalOption(WellKnownGlobalOption option, string? language) + => _inProc.GetGlobalOption(option, language); + + public void SetGlobalOption(WellKnownGlobalOption option, string? language, object? value) + => _inProc.SetGlobalOption(option, language, value); + public string? GetWorkingFolder() => _inProc.GetWorkingFolder(); } } diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstance.cs b/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstance.cs index 4df753b95095b..a812f141151f7 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstance.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/VisualStudioInstance.cs @@ -309,7 +309,7 @@ private void CloseRemotingService(bool allowInProcCalls) } } - private void StartRemoteIntegrationService(DTE dte) + private static void StartRemoteIntegrationService(DTE dte) { // We use DTE over RPC to start the integration service. All other DTE calls should happen in the host process. if (dte.Commands.Item(WellKnownCommandNames.Test_IntegrationTestService_Start).IsAvailable) diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/WellKnownCommandNames.cs b/src/VisualStudio/IntegrationTest/TestUtilities/WellKnownCommandNames.cs index 9bcd21c2cbcd8..0fb3cb90f7f27 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/WellKnownCommandNames.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/WellKnownCommandNames.cs @@ -12,6 +12,7 @@ public static class WellKnownCommandNames public const string Edit_GoToAll = "Edit.GoToAll"; public const string Edit_GoToDefinition = "Edit.GoToDefinition"; public const string Edit_GoToImplementation = "Edit.GoToImplementation"; + public const string Edit_GoToBase = "Edit.GoToBase"; public const string Edit_ListMembers = "Edit.ListMembers"; public const string Edit_ParameterInfo = "Edit.ParameterInfo"; public const string Edit_ToggleCompletionMode = "Edit.ToggleCompletionMode"; diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/WellKnownGlobalOptions.cs b/src/VisualStudio/IntegrationTest/TestUtilities/WellKnownGlobalOptions.cs new file mode 100644 index 0000000000000..cab93355e0a2c --- /dev/null +++ b/src/VisualStudio/IntegrationTest/TestUtilities/WellKnownGlobalOptions.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 Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.Options; +using Roslyn.Utilities; + +namespace Microsoft.VisualStudio.IntegrationTest.Utilities +{ + /// + /// Options settable by integration tests. + /// + /// TODO: Options are currently explicitly listed since is not serializable. + /// https://github.com/dotnet/roslyn/issues/59267 + /// + public enum WellKnownGlobalOption + { + CompletionOptions_ShowItemsFromUnimportedNamespaces, + CompletionViewOptions_EnableArgumentCompletionSnippets, + CompletionOptions_TriggerInArgumentLists, + } + + public static class WellKnownGlobalOptions + { + public static IOption GetOption(this WellKnownGlobalOption option) + => option switch + { + WellKnownGlobalOption.CompletionOptions_ShowItemsFromUnimportedNamespaces => CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, + WellKnownGlobalOption.CompletionOptions_TriggerInArgumentLists => CompletionOptionsStorage.TriggerInArgumentLists, + WellKnownGlobalOption.CompletionViewOptions_EnableArgumentCompletionSnippets => CompletionViewOptions.EnableArgumentCompletionSnippets, + _ => throw ExceptionUtilities.Unreachable + }; + + public static OptionKey GetKey(this WellKnownGlobalOption option, string? language) + => new OptionKey(GetOption(option), language); + } +} diff --git a/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs b/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs index 48c14d0159ce6..a2957caafe808 100644 --- a/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs +++ b/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs @@ -339,7 +339,7 @@ private Document AddDocumentToProject(string filePath, string language, string p return CurrentSolution.GetDocument(docInfo.Id)!; } - private string? GetLanguage(string filePath) + private static string? GetLanguage(string filePath) { var fileExtension = Path.GetExtension(filePath).ToLower(); diff --git a/src/VisualStudio/Setup.Dependencies/Roslyn.VisualStudio.Setup.Dependencies.csproj b/src/VisualStudio/Setup.Dependencies/Roslyn.VisualStudio.Setup.Dependencies.csproj index 0c331c92ae5fc..bd9e5beeb2cd4 100644 --- a/src/VisualStudio/Setup.Dependencies/Roslyn.VisualStudio.Setup.Dependencies.csproj +++ b/src/VisualStudio/Setup.Dependencies/Roslyn.VisualStudio.Setup.Dependencies.csproj @@ -29,12 +29,15 @@ + + + @@ -55,6 +58,7 @@ + @@ -62,6 +66,7 @@ +