diff --git a/.vsts-ci.yml b/.vsts-ci.yml
index 23eac359e..5f66064b0 100644
--- a/.vsts-ci.yml
+++ b/.vsts-ci.yml
@@ -12,12 +12,18 @@ variables:
# Branches that trigger a build on commit
trigger:
- main
+- dev17.0
stages:
- stage: build
displayName: Build and Test
jobs:
+ - template: /eng/common/templates/job/onelocbuild.yml
+ parameters:
+ LclSource: lclFilesfromPackage
+ LclPackageId: 'LCL-JUNO-PROD-ROSLYNSDK'
+
- job: OfficialBuild
displayName: Official Build
pool:
@@ -72,7 +78,7 @@ stages:
PathtoPublish: '$(Build.SourcesDirectory)\artifacts\log\$(BuildConfiguration)'
ArtifactName: 'Logs'
continueOnError: true
- condition: not(succeeded())
+ condition: always()
# Publish an artifact that the RoslynInsertionTool is able to find by its name.
- task: PublishBuildArtifacts@1
@@ -115,6 +121,7 @@ stages:
- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- template: eng\common\templates\post-build\post-build.yml
parameters:
+ publishingInfraVersion: 3
# Symbol validation is not entirely reliable as of yet, so should be turned off until
# https://github.com/dotnet/arcade/issues/2871 is resolved.
enableSymbolValidation: false
diff --git a/.vsts-pr.yaml b/.vsts-pr.yaml
index ab86e2cdc..8f1ccdb33 100644
--- a/.vsts-pr.yaml
+++ b/.vsts-pr.yaml
@@ -1,3 +1,13 @@
+# Branches that trigger a build on commit
+trigger:
+- main
+- dev17.0
+
+# Branches that trigger builds on PR
+pr:
+- main
+- dev17.0
+
variables:
- name: DOTNET_ROOT
value: $(Build.SourcesDirectory)\.dotnet
diff --git a/NuGet.config b/NuGet.config
index 712e69220..9680657aa 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -8,6 +8,7 @@
+
diff --git a/Roslyn-SDK.sln b/Roslyn-SDK.sln
index ef1484fb0..ae7e94b1b 100644
--- a/Roslyn-SDK.sln
+++ b/Roslyn-SDK.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.29814.53
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31706.66
MinimumVisualStudioVersion = 15.0.26124.0
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{924F7971-780C-4E70-A306-86482469502E}"
EndProject
@@ -191,6 +191,10 @@ Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "Microsoft.CodeAnalysis.Visu
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Roslyn.ComponentDebugger", "src\VisualStudio.Roslyn.SDK\ComponentDebugger\Roslyn.ComponentDebugger.csproj", "{421DE59C-8246-4679-9D69-79F16A7187BE}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "util", "util", "{7A94E723-ADD6-48C4-BBE7-1D5B311187A8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssemblyVersionGenerator", "src\VisualStudio.Roslyn.SDK\AssemblyVersionGenerator\AssemblyVersionGenerator.csproj", "{AB6B3C69-9F6F-461C-BFD8-D3F25B9F44AD}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -545,6 +549,10 @@ Global
{421DE59C-8246-4679-9D69-79F16A7187BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{421DE59C-8246-4679-9D69-79F16A7187BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{421DE59C-8246-4679-9D69-79F16A7187BE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AB6B3C69-9F6F-461C-BFD8-D3F25B9F44AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AB6B3C69-9F6F-461C-BFD8-D3F25B9F44AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AB6B3C69-9F6F-461C-BFD8-D3F25B9F44AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AB6B3C69-9F6F-461C-BFD8-D3F25B9F44AD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -642,6 +650,7 @@ Global
{7C3FE60E-055B-4E0C-BB85-C7E94A640074} = {9905147E-CC1F-42A0-BD27-05586C583DF7}
{92BD1781-5DB4-4F72-BCCB-0D64C0790A2B} = {9905147E-CC1F-42A0-BD27-05586C583DF7}
{421DE59C-8246-4679-9D69-79F16A7187BE} = {F9B73995-76C6-4056-ADA9-18342F951361}
+ {AB6B3C69-9F6F-461C-BFD8-D3F25B9F44AD} = {7A94E723-ADD6-48C4-BBE7-1D5B311187A8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {56695AA9-EA80-47A7-8562-E51285906C54}
diff --git a/Samples.sln b/Samples.sln
index 349b0c8cd..71d51bee6 100644
--- a/Samples.sln
+++ b/Samples.sln
@@ -1,4 +1,4 @@
-
+
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28606.18
@@ -113,9 +113,15 @@ Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "VisualBasicToCSharpConverte
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SourceGenerators", "SourceGenerators", "{14D18F51-6B59-49D5-9AB7-08B38417A459}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SourceGeneratorSamples", "samples\CSharp\SourceGenerators\SourceGeneratorSamples\SourceGeneratorSamples.csproj", "{2ADE5CFA-5DF4-44A9-BD67-E884BCFBA045}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSharpSourceGeneratorSamples", "samples\CSharp\SourceGenerators\SourceGeneratorSamples\CSharpSourceGeneratorSamples.csproj", "{2ADE5CFA-5DF4-44A9-BD67-E884BCFBA045}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeneratedDemo", "samples\CSharp\SourceGenerators\GeneratedDemo\GeneratedDemo.csproj", "{EC4DB63B-C2B4-4D06-AF98-15253035C6D5}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSharpGeneratedDemo", "samples\CSharp\SourceGenerators\GeneratedDemo\CSharpGeneratedDemo.csproj", "{EC4DB63B-C2B4-4D06-AF98-15253035C6D5}"
+EndProject
+Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "VisualBasicGeneratedDemo", "samples\VisualBasic\SourceGenerators\GeneratedDemo\VisualBasicGeneratedDemo.vbproj", "{DA924876-9CF5-47E0-AA01-ADAF47653D39}"
+EndProject
+Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "VisualBasicSourceGeneratorSamples", "samples\VisualBasic\SourceGenerators\SourceGeneratorSamples\VisualBasicSourceGeneratorSamples.vbproj", "{8322B6E4-0CB1-4EC1-A2CC-2E4DB02C834A}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SourceGenerators", "SourceGenerators", "{E79B07C8-0859-4B5C-9650-68D855833C6E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -283,6 +289,14 @@ Global
{EC4DB63B-C2B4-4D06-AF98-15253035C6D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC4DB63B-C2B4-4D06-AF98-15253035C6D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC4DB63B-C2B4-4D06-AF98-15253035C6D5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DA924876-9CF5-47E0-AA01-ADAF47653D39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DA924876-9CF5-47E0-AA01-ADAF47653D39}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DA924876-9CF5-47E0-AA01-ADAF47653D39}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DA924876-9CF5-47E0-AA01-ADAF47653D39}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8322B6E4-0CB1-4EC1-A2CC-2E4DB02C834A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8322B6E4-0CB1-4EC1-A2CC-2E4DB02C834A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8322B6E4-0CB1-4EC1-A2CC-2E4DB02C834A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8322B6E4-0CB1-4EC1-A2CC-2E4DB02C834A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -342,6 +356,9 @@ Global
{14D18F51-6B59-49D5-9AB7-08B38417A459} = {C3FB27E9-C8EE-4F76-B0AA-7CD67A7E652B}
{2ADE5CFA-5DF4-44A9-BD67-E884BCFBA045} = {14D18F51-6B59-49D5-9AB7-08B38417A459}
{EC4DB63B-C2B4-4D06-AF98-15253035C6D5} = {14D18F51-6B59-49D5-9AB7-08B38417A459}
+ {DA924876-9CF5-47E0-AA01-ADAF47653D39} = {E79B07C8-0859-4B5C-9650-68D855833C6E}
+ {8322B6E4-0CB1-4EC1-A2CC-2E4DB02C834A} = {E79B07C8-0859-4B5C-9650-68D855833C6E}
+ {E79B07C8-0859-4B5C-9650-68D855833C6E} = {CDA94F62-E35A-4913-8045-D9D42416513C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B849838B-3D7A-4B6B-BE07-285DCB1588F4}
diff --git a/eng/Publishing.props b/eng/Publishing.props
new file mode 100644
index 000000000..797de4ea1
--- /dev/null
+++ b/eng/Publishing.props
@@ -0,0 +1,6 @@
+
+
+
+ 3
+
+
\ No newline at end of file
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 52d5f57f6..90c1df549 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -3,9 +3,9 @@
-
+ https://github.com/dotnet/arcade
- db49d790a4bfa977a9ed7436bf2aa242cefae45e
+ 85a65ea1fca1d0867f699fed44d191358270bf6a
diff --git a/eng/Versions.props b/eng/Versions.props
index 9358a5cd8..5e8ce06d3 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -3,13 +3,14 @@
4.0.0
- 1.0.1
+ 1.1.1beta1truetruetruetrue
+ true3.9.016.1.1
@@ -61,12 +62,14 @@
17.0.0-beta1-10413-0217.0.0-beta1-10413-02
+ 17.0.667-pre
- 1.4.4
+ 1.5.02.6.13.9.01.0.1-beta1.20374.2
+ $(xunitVersion)1.2.70.1.49-beta
diff --git a/eng/common/build.ps1 b/eng/common/build.ps1
index 94a91c081..8943da242 100644
--- a/eng/common/build.ps1
+++ b/eng/common/build.ps1
@@ -25,6 +25,7 @@ Param(
[switch] $prepareMachine,
[string] $runtimeSourceFeed = '',
[string] $runtimeSourceFeedKey = '',
+ [switch] $excludePrereleaseVS,
[switch] $help,
[Parameter(ValueFromRemainingArguments=$true)][String[]]$properties
)
@@ -65,6 +66,7 @@ function Print-Usage() {
Write-Host " -prepareMachine Prepare machine for CI run, clean up processes after build"
Write-Host " -warnAsError Sets warnaserror msbuild parameter ('true' or 'false')"
Write-Host " -msbuildEngine Msbuild engine to use to run build ('dotnet', 'vs', or unspecified)."
+ Write-Host " -excludePrereleaseVS Set to exclude build engines in prerelease versions of Visual Studio"
Write-Host ""
Write-Host "Command line arguments not listed above are passed thru to msbuild."
diff --git a/eng/common/cross/build-android-rootfs.sh b/eng/common/cross/build-android-rootfs.sh
index c29c8267e..42516bbee 100755
--- a/eng/common/cross/build-android-rootfs.sh
+++ b/eng/common/cross/build-android-rootfs.sh
@@ -106,7 +106,6 @@ __AndroidPackages+=" libandroid-glob"
__AndroidPackages+=" liblzma"
__AndroidPackages+=" krb5"
__AndroidPackages+=" openssl"
-__AndroidPackages+=" openldap"
for path in $(wget -qO- http://termux.net/dists/stable/main/binary-$__AndroidArch/Packages |\
grep -A15 "Package: \(${__AndroidPackages// /\\|}\)" | grep -v "static\|tool" | grep Filename); do
diff --git a/eng/common/cross/build-rootfs.sh b/eng/common/cross/build-rootfs.sh
index 81e641a57..591d8666a 100755
--- a/eng/common/cross/build-rootfs.sh
+++ b/eng/common/cross/build-rootfs.sh
@@ -55,13 +55,11 @@ __UbuntuPackages+=" libcurl4-openssl-dev"
__UbuntuPackages+=" libkrb5-dev"
__UbuntuPackages+=" libssl-dev"
__UbuntuPackages+=" zlib1g-dev"
-__UbuntuPackages+=" libldap2-dev"
__AlpinePackages+=" curl-dev"
__AlpinePackages+=" krb5-dev"
__AlpinePackages+=" openssl-dev"
__AlpinePackages+=" zlib-dev"
-__AlpinePackages+=" openldap-dev"
__FreeBSDBase="12.1-RELEASE"
__FreeBSDPkg="1.12.0"
@@ -70,13 +68,15 @@ __FreeBSDPackages+=" icu"
__FreeBSDPackages+=" libinotify"
__FreeBSDPackages+=" lttng-ust"
__FreeBSDPackages+=" krb5"
-__FreeBSDPackages+=" libslapi-2.4"
__IllumosPackages="icu-64.2nb2"
__IllumosPackages+=" mit-krb5-1.16.2nb4"
__IllumosPackages+=" openssl-1.1.1e"
__IllumosPackages+=" zlib-1.2.11"
-__IllumosPackages+=" openldap-client-2.4.49"
+
+# ML.NET dependencies
+__UbuntuPackages+=" libomp5"
+__UbuntuPackages+=" libomp-dev"
__UseMirror=0
diff --git a/eng/common/generate-locproject.ps1 b/eng/common/generate-locproject.ps1
index 7225ddc66..de348a2e2 100644
--- a/eng/common/generate-locproject.ps1
+++ b/eng/common/generate-locproject.ps1
@@ -14,7 +14,7 @@ $ErrorActionPreference = "Stop"
Import-Module -Name (Join-Path $PSScriptRoot 'native\CommonLibrary.psm1')
-$exclusionsFilePath = "$SourcesDirectory\Localize\LocExclusions.json"
+$exclusionsFilePath = "$SourcesDirectory\eng\Localize\LocExclusions.json"
$exclusions = @{ Exclusions = @() }
if (Test-Path -Path $exclusionsFilePath)
{
@@ -66,10 +66,19 @@ $locJson = @{
}
if ($continue)
{
- return @{
- SourceFile = $sourceFile
- CopyOption = "LangIDOnName"
- OutputPath = $outputPath
+ if ($_.Directory.Name -eq 'en' -and $_.Extension -eq '.json') {
+ return @{
+ SourceFile = $sourceFile
+ CopyOption = "LangIDOnPath"
+ OutputPath = "$($_.Directory.Parent.FullName | Resolve-Path -Relative)\"
+ }
+ }
+ else {
+ return @{
+ SourceFile = $sourceFile
+ CopyOption = "LangIDOnName"
+ OutputPath = $outputPath
+ }
}
}
}
@@ -83,14 +92,14 @@ Write-Host "LocProject.json generated:`n`n$json`n`n"
Pop-Location
if (!$UseCheckedInLocProjectJson) {
- New-Item "$SourcesDirectory\Localize\LocProject.json" -Force # Need this to make sure the Localize directory is created
- Set-Content "$SourcesDirectory\Localize\LocProject.json" $json
+ New-Item "$SourcesDirectory\eng\Localize\LocProject.json" -Force # Need this to make sure the Localize directory is created
+ Set-Content "$SourcesDirectory\eng\Localize\LocProject.json" $json
}
else {
- New-Item "$SourcesDirectory\Localize\LocProject-generated.json" -Force # Need this to make sure the Localize directory is created
- Set-Content "$SourcesDirectory\Localize\LocProject-generated.json" $json
+ New-Item "$SourcesDirectory\eng\Localize\LocProject-generated.json" -Force # Need this to make sure the Localize directory is created
+ Set-Content "$SourcesDirectory\eng\Localize\LocProject-generated.json" $json
- if ((Get-FileHash "$SourcesDirectory\Localize\LocProject-generated.json").Hash -ne (Get-FileHash "$SourcesDirectory\Localize\LocProject.json").Hash) {
+ if ((Get-FileHash "$SourcesDirectory\eng\Localize\LocProject-generated.json").Hash -ne (Get-FileHash "$SourcesDirectory\eng\Localize\LocProject.json").Hash) {
Write-PipelineTelemetryError -Category "OneLocBuild" -Message "Existing LocProject.json differs from generated LocProject.json. Download LocProject-generated.json and compare them."
exit 1
diff --git a/eng/common/msbuild.ps1 b/eng/common/msbuild.ps1
index c64012300..eea19cd84 100644
--- a/eng/common/msbuild.ps1
+++ b/eng/common/msbuild.ps1
@@ -5,6 +5,7 @@ Param(
[bool] $nodeReuse = $true,
[switch] $ci,
[switch] $prepareMachine,
+ [switch] $excludePrereleaseVS,
[Parameter(ValueFromRemainingArguments=$true)][String[]]$extraArgs
)
diff --git a/eng/common/post-build/sourcelink-validation.ps1 b/eng/common/post-build/sourcelink-validation.ps1
index 1c46f7b63..85c898617 100644
--- a/eng/common/post-build/sourcelink-validation.ps1
+++ b/eng/common/post-build/sourcelink-validation.ps1
@@ -14,7 +14,9 @@ param(
$global:RepoFiles = @{}
# Maximum number of jobs to run in parallel
-$MaxParallelJobs = 6
+$MaxParallelJobs = 16
+
+$MaxRetries = 5
# Wait time between check for system load
$SecondsBetweenLoadChecks = 10
@@ -29,7 +31,10 @@ $ValidatePackage = {
# Ensure input file exist
if (!(Test-Path $PackagePath)) {
Write-Host "Input file does not exist: $PackagePath"
- return 1
+ return [pscustomobject]@{
+ result = 1
+ packagePath = $PackagePath
+ }
}
# Extensions for which we'll look for SourceLink information
@@ -59,7 +64,10 @@ $ValidatePackage = {
# We ignore resource DLLs
if ($FileName.EndsWith('.resources.dll')) {
- return
+ return [pscustomobject]@{
+ result = 0
+ packagePath = $PackagePath
+ }
}
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $TargetFile, $true)
@@ -91,36 +99,49 @@ $ValidatePackage = {
$Status = 200
$Cache = $using:RepoFiles
- if ( !($Cache.ContainsKey($FilePath)) ) {
- try {
- $Uri = $Link -as [System.URI]
-
- # Only GitHub links are valid
- if ($Uri.AbsoluteURI -ne $null -and ($Uri.Host -match 'github' -or $Uri.Host -match 'githubusercontent')) {
- $Status = (Invoke-WebRequest -Uri $Link -UseBasicParsing -Method HEAD -TimeoutSec 5).StatusCode
+ $totalRetries = 0
+
+ while ($totalRetries -lt $using:MaxRetries) {
+ if ( !($Cache.ContainsKey($FilePath)) ) {
+ try {
+ $Uri = $Link -as [System.URI]
+
+ # Only GitHub links are valid
+ if ($Uri.AbsoluteURI -ne $null -and ($Uri.Host -match 'github' -or $Uri.Host -match 'githubusercontent')) {
+ $Status = (Invoke-WebRequest -Uri $Link -UseBasicParsing -Method HEAD -TimeoutSec 5).StatusCode
+ }
+ else {
+ # If it's not a github link, we want to break out of the loop and not retry.
+ $Status = 0
+ $totalRetries = $using:MaxRetries
+ }
}
- else {
+ catch {
+ Write-Host $_
$Status = 0
}
}
- catch {
- write-host $_
- $Status = 0
- }
- }
- if ($Status -ne 200) {
- if ($NumFailedLinks -eq 0) {
- if ($FailedFiles.Value -eq 0) {
- Write-Host
+ if ($Status -ne 200) {
+ $totalRetries++
+
+ if ($totalRetries -ge $using:MaxRetries) {
+ if ($NumFailedLinks -eq 0) {
+ if ($FailedFiles.Value -eq 0) {
+ Write-Host
+ }
+
+ Write-Host "`tFile $RealPath has broken links:"
+ }
+
+ Write-Host "`t`tFailed to retrieve $Link"
+
+ $NumFailedLinks++
}
-
- Write-Host "`tFile $RealPath has broken links:"
}
-
- Write-Host "`t`tFailed to retrieve $Link"
-
- $NumFailedLinks++
+ else {
+ break
+ }
}
}
}
@@ -136,7 +157,7 @@ $ValidatePackage = {
}
}
catch {
-
+ Write-Host $_
}
finally {
$zip.Dispose()
@@ -220,6 +241,7 @@ function ValidateSourceLinkLinks {
# Process each NuGet package in parallel
Get-ChildItem "$InputPath\*.symbols.nupkg" |
ForEach-Object {
+ Write-Host "Starting $($_.FullName)"
Start-Job -ScriptBlock $ValidatePackage -ArgumentList $_.FullName | Out-Null
$NumJobs = @(Get-Job -State 'Running').Count
@@ -267,6 +289,10 @@ function InstallSourcelinkCli {
try {
InstallSourcelinkCli
+ foreach ($Job in @(Get-Job)) {
+ Remove-Job -Id $Job.Id
+ }
+
ValidateSourceLinkLinks
}
catch {
diff --git a/eng/common/post-build/symbols-validation.ps1 b/eng/common/post-build/symbols-validation.ps1
index 99bf28cd5..a5af041ba 100644
--- a/eng/common/post-build/symbols-validation.ps1
+++ b/eng/common/post-build/symbols-validation.ps1
@@ -1,13 +1,14 @@
param(
- [Parameter(Mandatory=$true)][string] $InputPath, # Full path to directory where NuGet packages to be checked are stored
- [Parameter(Mandatory=$true)][string] $ExtractPath, # Full path to directory where the packages will be extracted during validation
- [Parameter(Mandatory=$true)][string] $DotnetSymbolVersion, # Version of dotnet symbol to use
- [Parameter(Mandatory=$false)][switch] $ContinueOnError, # If we should keep checking symbols after an error
- [Parameter(Mandatory=$false)][switch] $Clean # Clean extracted symbols directory after checking symbols
+ [Parameter(Mandatory = $true)][string] $InputPath, # Full path to directory where NuGet packages to be checked are stored
+ [Parameter(Mandatory = $true)][string] $ExtractPath, # Full path to directory where the packages will be extracted during validation
+ [Parameter(Mandatory = $true)][string] $DotnetSymbolVersion, # Version of dotnet symbol to use
+ [Parameter(Mandatory = $false)][switch] $CheckForWindowsPdbs, # If we should check for the existence of windows pdbs in addition to portable PDBs
+ [Parameter(Mandatory = $false)][switch] $ContinueOnError, # If we should keep checking symbols after an error
+ [Parameter(Mandatory = $false)][switch] $Clean # Clean extracted symbols directory after checking symbols
)
# Maximum number of jobs to run in parallel
-$MaxParallelJobs = 6
+$MaxParallelJobs = 16
# Max number of retries
$MaxRetry = 5
@@ -19,9 +20,15 @@ $SecondsBetweenLoadChecks = 10
Set-Variable -Name "ERROR_BADEXTRACT" -Option Constant -Value -1
Set-Variable -Name "ERROR_FILEDOESNOTEXIST" -Option Constant -Value -2
+$WindowsPdbVerificationParam = ""
+if ($CheckForWindowsPdbs) {
+ $WindowsPdbVerificationParam = "--windows-pdbs"
+}
+
$CountMissingSymbols = {
param(
- [string] $PackagePath # Path to a NuGet package
+ [string] $PackagePath, # Path to a NuGet package
+ [string] $WindowsPdbVerificationParam # If we should check for the existence of windows pdbs in addition to portable PDBs
)
. $using:PSScriptRoot\..\tools.ps1
@@ -34,7 +41,7 @@ $CountMissingSymbols = {
if (!(Test-Path $PackagePath)) {
Write-PipelineTaskError "Input file does not exist: $PackagePath"
return [pscustomobject]@{
- result = $using:ERROR_FILEDOESNOTEXIST
+ result = $using:ERROR_FILEDOESNOTEXIST
packagePath = $PackagePath
}
}
@@ -57,24 +64,25 @@ $CountMissingSymbols = {
Write-Host "Something went wrong extracting $PackagePath"
Write-Host $_
return [pscustomobject]@{
- result = $using:ERROR_BADEXTRACT
+ result = $using:ERROR_BADEXTRACT
packagePath = $PackagePath
}
}
Get-ChildItem -Recurse $ExtractPath |
- Where-Object {$RelevantExtensions -contains $_.Extension} |
- ForEach-Object {
- $FileName = $_.FullName
- if ($FileName -Match '\\ref\\') {
- Write-Host "`t Ignoring reference assembly file " $FileName
- return
- }
+ Where-Object { $RelevantExtensions -contains $_.Extension } |
+ ForEach-Object {
+ $FileName = $_.FullName
+ if ($FileName -Match '\\ref\\') {
+ Write-Host "`t Ignoring reference assembly file " $FileName
+ return
+ }
- $FirstMatchingSymbolDescriptionOrDefault = {
+ $FirstMatchingSymbolDescriptionOrDefault = {
param(
- [string] $FullPath, # Full path to the module that has to be checked
- [string] $TargetServerParam, # Parameter to pass to `Symbol Tool` indicating the server to lookup for symbols
+ [string] $FullPath, # Full path to the module that has to be checked
+ [string] $TargetServerParam, # Parameter to pass to `Symbol Tool` indicating the server to lookup for symbols
+ [string] $WindowsPdbVerificationParam, # Parameter to pass to potential check for windows-pdbs.
[string] $SymbolsPath
)
@@ -99,15 +107,16 @@ $CountMissingSymbols = {
# DWARF file for a .dylib
$DylibDwarf = $SymbolPath.Replace($Extension, '.dylib.dwarf')
-
+
$dotnetSymbolExe = "$env:USERPROFILE\.dotnet\tools"
$dotnetSymbolExe = Resolve-Path "$dotnetSymbolExe\dotnet-symbol.exe"
$totalRetries = 0
while ($totalRetries -lt $using:MaxRetry) {
+
# Save the output and get diagnostic output
- $output = & $dotnetSymbolExe --symbols --modules --windows-pdbs $TargetServerParam $FullPath -o $SymbolsPath --diagnostics | Out-String
+ $output = & $dotnetSymbolExe --symbols --modules $WindowsPdbVerificationParam $TargetServerParam $FullPath -o $SymbolsPath --diagnostics | Out-String
if (Test-Path $PdbPath) {
return 'PDB'
@@ -124,42 +133,50 @@ $CountMissingSymbols = {
elseif (Test-Path $SymbolPath) {
return 'Module'
}
- elseif ($output.Contains("503 Service Unavailable")) {
- # If we got a 503 error, we should retry.
+ else
+ {
$totalRetries++
}
- else {
- return $null
- }
}
return $null
}
- $SymbolsOnMSDL = & $FirstMatchingSymbolDescriptionOrDefault $FileName '--microsoft-symbol-server' $SymbolsPath
- $SymbolsOnSymWeb = & $FirstMatchingSymbolDescriptionOrDefault $FileName '--internal-server' $SymbolsPath
-
- Write-Host -NoNewLine "`t Checking file " $FileName "... "
+ $FileGuid = New-Guid
+ $ExpandedSymbolsPath = Join-Path -Path $SymbolsPath -ChildPath $FileGuid
+
+ $SymbolsOnMSDL = & $FirstMatchingSymbolDescriptionOrDefault `
+ -FullPath $FileName `
+ -TargetServerParam '--microsoft-symbol-server' `
+ -SymbolsPath "$ExpandedSymbolsPath-msdl" `
+ -WindowsPdbVerificationParam $WindowsPdbVerificationParam
+ $SymbolsOnSymWeb = & $FirstMatchingSymbolDescriptionOrDefault `
+ -FullPath $FileName `
+ -TargetServerParam '--internal-server' `
+ -SymbolsPath "$ExpandedSymbolsPath-symweb" `
+ -WindowsPdbVerificationParam $WindowsPdbVerificationParam
+
+ Write-Host -NoNewLine "`t Checking file " $FileName "... "
- if ($SymbolsOnMSDL -ne $null -and $SymbolsOnSymWeb -ne $null) {
- Write-Host "Symbols found on MSDL ($SymbolsOnMSDL) and SymWeb ($SymbolsOnSymWeb)"
+ if ($SymbolsOnMSDL -ne $null -and $SymbolsOnSymWeb -ne $null) {
+ Write-Host "Symbols found on MSDL ($SymbolsOnMSDL) and SymWeb ($SymbolsOnSymWeb)"
+ }
+ else {
+ $MissingSymbols++
+
+ if ($SymbolsOnMSDL -eq $null -and $SymbolsOnSymWeb -eq $null) {
+ Write-Host 'No symbols found on MSDL or SymWeb!'
}
else {
- $MissingSymbols++
-
- if ($SymbolsOnMSDL -eq $null -and $SymbolsOnSymWeb -eq $null) {
- Write-Host 'No symbols found on MSDL or SymWeb!'
+ if ($SymbolsOnMSDL -eq $null) {
+ Write-Host 'No symbols found on MSDL!'
}
else {
- if ($SymbolsOnMSDL -eq $null) {
- Write-Host 'No symbols found on MSDL!'
- }
- else {
- Write-Host 'No symbols found on SymWeb!'
- }
+ Write-Host 'No symbols found on SymWeb!'
}
}
}
+ }
if ($using:Clean) {
Remove-Item $ExtractPath -Recurse -Force
@@ -168,16 +185,16 @@ $CountMissingSymbols = {
Pop-Location
return [pscustomobject]@{
- result = $MissingSymbols
- packagePath = $PackagePath
- }
+ result = $MissingSymbols
+ packagePath = $PackagePath
+ }
}
function CheckJobResult(
- $result,
- $packagePath,
- [ref]$DupedSymbols,
- [ref]$TotalFailures) {
+ $result,
+ $packagePath,
+ [ref]$DupedSymbols,
+ [ref]$TotalFailures) {
if ($result -eq $ERROR_BADEXTRACT) {
Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "$packagePath has duplicated symbol files"
$DupedSymbols.Value++
@@ -200,6 +217,7 @@ function CheckSymbolsAvailable {
Remove-Item $ExtractPath -Force -Recurse -ErrorAction SilentlyContinue
}
+ $TotalPackages = 0
$TotalFailures = 0
$DupedSymbols = 0
@@ -222,7 +240,9 @@ function CheckSymbolsAvailable {
return
}
- Start-Job -ScriptBlock $CountMissingSymbols -ArgumentList $FullName | Out-Null
+ $TotalPackages++
+
+ Start-Job -ScriptBlock $CountMissingSymbols -ArgumentList @($FullName,$WindowsPdbVerificationParam) | Out-Null
$NumJobs = @(Get-Job -State 'Running').Count
@@ -247,11 +267,11 @@ function CheckSymbolsAvailable {
if ($TotalFailures -gt 0 -or $DupedSymbols -gt 0) {
if ($TotalFailures -gt 0) {
- Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "Symbols missing for $TotalFailures packages"
+ Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "Symbols missing for $TotalFailures/$TotalPackages packages"
}
if ($DupedSymbols -gt 0) {
- Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "$DupedSymbols packages had duplicated symbol files"
+ Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "$DupedSymbols/$TotalPackages packages had duplicated symbol files and could not be extracted"
}
ExitWithExitCode 1
diff --git a/eng/common/sdk-task.ps1 b/eng/common/sdk-task.ps1
index f55c43c6f..65f1d75f3 100644
--- a/eng/common/sdk-task.ps1
+++ b/eng/common/sdk-task.ps1
@@ -53,7 +53,7 @@ try {
}
if ($task -eq "") {
- Write-PipelineTelemetryError -Category 'Build' -Message "Missing required parameter '-task '" -ForegroundColor Red
+ Write-PipelineTelemetryError -Category 'Build' -Message "Missing required parameter '-task '"
Print-Usage
ExitWithExitCode 1
}
@@ -78,7 +78,7 @@ try {
$taskProject = GetSdkTaskProject $task
if (!(Test-Path $taskProject)) {
- Write-PipelineTelemetryError -Category 'Build' -Message "Unknown task: $task" -ForegroundColor Red
+ Write-PipelineTelemetryError -Category 'Build' -Message "Unknown task: $task"
ExitWithExitCode 1
}
diff --git a/eng/common/templates/job/onelocbuild.yml b/eng/common/templates/job/onelocbuild.yml
index 928a70cda..2acdd5256 100644
--- a/eng/common/templates/job/onelocbuild.yml
+++ b/eng/common/templates/job/onelocbuild.yml
@@ -11,11 +11,14 @@ parameters:
SourcesDirectory: $(Build.SourcesDirectory)
CreatePr: true
+ AutoCompletePr: false
+ UseLfLineEndings: true
UseCheckedInLocProjectJson: false
LanguageSet: VS_Main_Languages
LclSource: lclFilesInRepo
LclPackageId: ''
RepoType: gitHub
+ condition: ''
jobs:
- job: OneLocBuild
@@ -43,23 +46,27 @@ jobs:
filePath: $(Build.SourcesDirectory)/eng/common/generate-locproject.ps1
arguments: $(_GenerateLocProjectArguments)
displayName: Generate LocProject.json
+ condition: ${{ parameters.condition }}
- task: OneLocBuild@2
displayName: OneLocBuild
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
inputs:
- locProj: Localize/LocProject.json
+ locProj: eng/Localize/LocProject.json
outDir: $(Build.ArtifactStagingDirectory)
lclSource: ${{ parameters.LclSource }}
lclPackageId: ${{ parameters.LclPackageId }}
isCreatePrSelected: ${{ parameters.CreatePr }}
+ ${{ if eq(parameters.CreatePr, true) }}:
+ isAutoCompletePrSelected: ${{ parameters.AutoCompletePr }}
+ isUseLfLineEndingsSelected: ${{ parameters.UseLfLineEndings }}
packageSourceAuth: patAuth
patVariable: ${{ parameters.CeapexPat }}
${{ if eq(parameters.RepoType, 'gitHub') }}:
repoType: ${{ parameters.RepoType }}
gitHubPatVariable: "${{ parameters.GithubPat }}"
- condition: always()
+ condition: ${{ parameters.condition }}
- task: PublishBuildArtifacts@1
displayName: Publish Localization Files
@@ -67,12 +74,12 @@ jobs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)/loc'
PublishLocation: Container
ArtifactName: Loc
- condition: always()
+ condition: ${{ parameters.condition }}
- task: PublishBuildArtifacts@1
displayName: Publish LocProject.json
inputs:
- PathtoPublish: '$(Build.SourcesDirectory)/Localize/'
+ PathtoPublish: '$(Build.SourcesDirectory)/eng/Localize/'
PublishLocation: Container
ArtifactName: Loc
- condition: always()
\ No newline at end of file
+ condition: ${{ parameters.condition }}
\ No newline at end of file
diff --git a/eng/common/templates/job/source-build.yml b/eng/common/templates/job/source-build.yml
index aad414649..5023d36dc 100644
--- a/eng/common/templates/job/source-build.yml
+++ b/eng/common/templates/job/source-build.yml
@@ -15,6 +15,9 @@ parameters:
# nonPortable: false
# Enables non-portable mode. This means a more specific RID (e.g. fedora.32-x64 rather than
# linux-x64), and compiling against distro-provided packages rather than portable ones.
+ # skipPublishValidation: false
+ # Disables publishing validation. By default, a check is performed to ensure no packages are
+ # published by source-build.
# container: ''
# A container to use. Runs in docker.
# pool: {}
diff --git a/eng/common/templates/job/source-index-stage1.yml b/eng/common/templates/job/source-index-stage1.yml
index c002a2b1b..a649d2b59 100644
--- a/eng/common/templates/job/source-index-stage1.yml
+++ b/eng/common/templates/job/source-index-stage1.yml
@@ -1,6 +1,6 @@
parameters:
runAsPublic: false
- sourceIndexPackageVersion: 1.0.1-20210225.1
+ sourceIndexPackageVersion: 1.0.1-20210421.1
sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json
sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci"
preSteps: []
diff --git a/eng/common/templates/post-build/channels/generic-internal-channel.yml b/eng/common/templates/post-build/channels/generic-internal-channel.yml
index 58fa9a35b..8990dfc8c 100644
--- a/eng/common/templates/post-build/channels/generic-internal-channel.yml
+++ b/eng/common/templates/post-build/channels/generic-internal-channel.yml
@@ -40,6 +40,9 @@ stages:
pool:
vmImage: 'windows-2019'
steps:
+ - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions."
+ displayName: Warn about v2 Arcade Publishing Usage
+
# This is necessary whenever we want to publish/restore to an AzDO private feed
- task: NuGetAuthenticate@0
displayName: 'Authenticate to AzDO Feeds'
@@ -110,6 +113,9 @@ stages:
pool:
vmImage: 'windows-2019'
steps:
+ - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions."
+ displayName: Warn about v2 Arcade Publishing Usage
+
- task: DownloadBuildArtifacts@0
displayName: Download Build Assets
continueOnError: true
diff --git a/eng/common/templates/post-build/channels/generic-public-channel.yml b/eng/common/templates/post-build/channels/generic-public-channel.yml
index b50c0b3bd..3220c6a4f 100644
--- a/eng/common/templates/post-build/channels/generic-public-channel.yml
+++ b/eng/common/templates/post-build/channels/generic-public-channel.yml
@@ -42,6 +42,9 @@ stages:
pool:
vmImage: 'windows-2019'
steps:
+ - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions."
+ displayName: Warn about v2 Arcade Publishing Usage
+
- task: DownloadBuildArtifacts@0
displayName: Download Build Assets
continueOnError: true
@@ -109,6 +112,9 @@ stages:
pool:
vmImage: 'windows-2019'
steps:
+ - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions."
+ displayName: Warn about v2 Arcade Publishing Usage
+
- task: DownloadBuildArtifacts@0
displayName: Download Build Assets
continueOnError: true
diff --git a/eng/common/templates/steps/source-build.yml b/eng/common/templates/steps/source-build.yml
index 65ee5992b..e20637ed6 100644
--- a/eng/common/templates/steps/source-build.yml
+++ b/eng/common/templates/steps/source-build.yml
@@ -34,9 +34,14 @@ steps:
targetRidArgs='/p:TargetRid=${{ parameters.platform.targetRID }}'
fi
+ publishArgs=
+ if [ '${{ parameters.platform.skipPublishValidation }}' != 'true' ]; then
+ publishArgs='--publish'
+ fi
+
${{ coalesce(parameters.platform.buildScript, './build.sh') }} --ci \
--configuration $buildConfig \
- --restore --build --pack --publish -bl \
+ --restore --build --pack $publishArgs -bl \
$officialBuildArgs \
$targetRidArgs \
/p:SourceBuildNonPortable=${{ parameters.platform.nonPortable }} \
diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1
index d52467eea..2d8a74f7d 100644
--- a/eng/common/tools.ps1
+++ b/eng/common/tools.ps1
@@ -48,6 +48,9 @@
# True to use global NuGet cache instead of restoring packages to repository-local directory.
[bool]$useGlobalNuGetCache = if (Test-Path variable:useGlobalNuGetCache) { $useGlobalNuGetCache } else { !$ci }
+# True to exclude prerelease versions Visual Studio during build
+[bool]$excludePrereleaseVS = if (Test-Path variable:excludePrereleaseVS) { $excludePrereleaseVS } else { $false }
+
# An array of names of processes to stop on script exit if prepareMachine is true.
$processesToStopOnExit = if (Test-Path variable:processesToStopOnExit) { $processesToStopOnExit } else { @('msbuild', 'dotnet', 'vbcscompiler') }
@@ -463,7 +466,11 @@ function LocateVisualStudio([object]$vsRequirements = $null){
}
if (!$vsRequirements) { $vsRequirements = $GlobalJson.tools.vs }
- $args = @('-latest', '-prerelease', '-format', 'json', '-requires', 'Microsoft.Component.MSBuild', '-products', '*')
+ $args = @('-latest', '-format', 'json', '-requires', 'Microsoft.Component.MSBuild', '-products', '*')
+
+ if (!$excludePrereleaseVS) {
+ $args += '-prerelease'
+ }
if (Get-Member -InputObject $vsRequirements -Name 'version') {
$args += '-version'
@@ -489,7 +496,13 @@ function LocateVisualStudio([object]$vsRequirements = $null){
function InitializeBuildTool() {
if (Test-Path variable:global:_BuildTool) {
- return $global:_BuildTool
+ # If the requested msbuild parameters do not match, clear the cached variables.
+ if($global:_BuildTool.Contains('ExcludePrereleaseVS') -and $global:_BuildTool.ExcludePrereleaseVS -ne $excludePrereleaseVS) {
+ Remove-Item variable:global:_BuildTool
+ Remove-Item variable:global:_MSBuildExe
+ } else {
+ return $global:_BuildTool
+ }
}
if (-not $msbuildEngine) {
@@ -517,7 +530,7 @@ function InitializeBuildTool() {
ExitWithExitCode 1
}
- $buildTool = @{ Path = $msbuildPath; Command = ""; Tool = "vs"; Framework = "net472" }
+ $buildTool = @{ Path = $msbuildPath; Command = ""; Tool = "vs"; Framework = "net472"; ExcludePrereleaseVS = $excludePrereleaseVS }
} else {
Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Unexpected value of -msbuildEngine: '$msbuildEngine'."
ExitWithExitCode 1
diff --git a/global.json b/global.json
index 7b55f2186..382a76cc4 100644
--- a/global.json
+++ b/global.json
@@ -1,11 +1,11 @@
{
"sdk": {
- "version": "6.0.100-preview.2.21155.3",
+ "version": "6.0.100-preview.3.21202.5",
"allowPrerelease": true,
"rollForward": "major"
},
"tools": {
- "dotnet": "6.0.100-preview.2.21155.3",
+ "dotnet": "6.0.100-preview.3.21202.5",
"runtimes": {
"dotnet": [
"3.1.0"
@@ -17,6 +17,6 @@
"xcopy-msbuild": "16.8.0-preview2.1"
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21212.6"
+ "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21304.1"
}
}
diff --git a/samples/CSharp/SourceGenerators/GeneratedDemo/GeneratedDemo.csproj b/samples/CSharp/SourceGenerators/GeneratedDemo/CSharpGeneratedDemo.csproj
similarity index 82%
rename from samples/CSharp/SourceGenerators/GeneratedDemo/GeneratedDemo.csproj
rename to samples/CSharp/SourceGenerators/GeneratedDemo/CSharpGeneratedDemo.csproj
index b95bde39c..4b3054e9f 100644
--- a/samples/CSharp/SourceGenerators/GeneratedDemo/GeneratedDemo.csproj
+++ b/samples/CSharp/SourceGenerators/GeneratedDemo/CSharpGeneratedDemo.csproj
@@ -13,7 +13,7 @@
-
+
diff --git a/samples/CSharp/SourceGenerators/README.md b/samples/CSharp/SourceGenerators/README.md
index fe06c349e..958cf03f6 100644
--- a/samples/CSharp/SourceGenerators/README.md
+++ b/samples/CSharp/SourceGenerators/README.md
@@ -28,7 +28,7 @@ You can add the sample generators to your own project by adding an item group co
```xml
-
+
```
diff --git a/samples/CSharp/SourceGenerators/SourceGeneratorSamples/SourceGeneratorSamples.csproj b/samples/CSharp/SourceGenerators/SourceGeneratorSamples/CSharpSourceGeneratorSamples.csproj
similarity index 100%
rename from samples/CSharp/SourceGenerators/SourceGeneratorSamples/SourceGeneratorSamples.csproj
rename to samples/CSharp/SourceGenerators/SourceGeneratorSamples/CSharpSourceGeneratorSamples.csproj
diff --git a/samples/CSharp/SourceGenerators/SourceGenerators.sln b/samples/CSharp/SourceGenerators/SourceGenerators.sln
index 1e5b737dc..1732a9c41 100644
--- a/samples/CSharp/SourceGenerators/SourceGenerators.sln
+++ b/samples/CSharp/SourceGenerators/SourceGenerators.sln
@@ -3,9 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30022.13
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SourceGeneratorSamples", "SourceGeneratorSamples\SourceGeneratorSamples.csproj", "{B452269D-856C-4FE6-8900-3D81461AF864}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SourceGeneratorSamples", "SourceGeneratorSamples\CSharpSourceGeneratorSamples.csproj", "{B452269D-856C-4FE6-8900-3D81461AF864}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeneratedDemo", "GeneratedDemo\GeneratedDemo.csproj", "{DB138C8B-7C34-4AC7-A443-A0B29D1CE8A5}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeneratedDemo", "GeneratedDemo\CSharpGeneratedDemo.csproj", "{DB138C8B-7C34-4AC7-A443-A0B29D1CE8A5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/Cars.csv b/samples/VisualBasic/SourceGenerators/GeneratedDemo/Cars.csv
new file mode 100644
index 000000000..26a5d2051
--- /dev/null
+++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/Cars.csv
@@ -0,0 +1,4 @@
+Brand, Model, Year, cc, Favorite
+Fiat, Punto, 2008, 12.3, No
+Ford, Wagon, 1956, 20.3, No
+BMW, "335", 2014, 20.3, Yes
\ No newline at end of file
diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/MainSettings.xmlsettings b/samples/VisualBasic/SourceGenerators/GeneratedDemo/MainSettings.xmlsettings
new file mode 100644
index 000000000..96b96f5e5
--- /dev/null
+++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/MainSettings.xmlsettings
@@ -0,0 +1,6 @@
+
+
+ False
+ 1234
+ Hello World!
+
\ No newline at end of file
diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/People.csv b/samples/VisualBasic/SourceGenerators/GeneratedDemo/People.csv
new file mode 100644
index 000000000..5179c3539
--- /dev/null
+++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/People.csv
@@ -0,0 +1,3 @@
+Name, address, 11Age
+"Luca Bol", "23 Bell Street", 90
+"john doe", "32 Carl street", 45
\ No newline at end of file
diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/Program.vb b/samples/VisualBasic/SourceGenerators/GeneratedDemo/Program.vb
new file mode 100644
index 000000000..fd209d06b
--- /dev/null
+++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/Program.vb
@@ -0,0 +1,33 @@
+Option Explicit On
+Option Strict On
+Option Infer On
+
+Module Program
+
+ Public Sub Main()
+
+ Console.WriteLine("Running HelloWorld:
+")
+ UseHelloWorldGenerator.Run()
+
+ Console.WriteLine("
+
+Running AutoNotify:
+")
+ UseAutoNotifyGenerator.Run()
+
+ Console.WriteLine("
+
+Running XmlSettings:
+")
+ UseXmlSettingsGenerator.Run()
+
+ Console.WriteLine("
+
+Running CsvGenerator:
+")
+ UseCsvGenerator.Run()
+
+ End Sub
+
+End Module
diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseAutoNotifyGenerator.vb b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseAutoNotifyGenerator.vb
new file mode 100644
index 000000000..f810bd4a6
--- /dev/null
+++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseAutoNotifyGenerator.vb
@@ -0,0 +1,42 @@
+Option Explicit On
+Option Strict On
+Option Infer On
+
+Imports AutoNotify
+
+' The view model we'd like to augment
+Partial Public Class ExampleViewModel
+
+
+ Private _text As String = "private field text"
+
+
+ Private _amount As Integer = 5
+
+End Class
+
+Public Module UseAutoNotifyGenerator
+
+ Public Sub Run()
+
+ Dim vm As New ExampleViewModel()
+
+ ' we didn't explicitly create the 'Text' property, it was generated for us
+ Dim text = vm.Text
+ Console.WriteLine($"Text = {text}")
+
+ ' Properties can have differnt names generated based on the PropertyName argument of the attribute
+ Dim count = vm.Count
+ Console.WriteLine($"Count = {count}")
+
+ ' the viewmodel will automatically implement INotifyPropertyChanged
+ AddHandler vm.PropertyChanged, Sub(o, e) Console.WriteLine($"Property {e.PropertyName} was changed")
+ vm.Text = "abc"
+ vm.Count = 123
+
+ ' Try adding fields to the ExampleViewModel class above and tagging them with the attribute
+ ' You'll see the matching generated properties visibile in IntelliSense in realtime
+
+ End Sub
+
+End Module
diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseCsvGenerator.vb b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseCsvGenerator.vb
new file mode 100644
index 000000000..f4c055835
--- /dev/null
+++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseCsvGenerator.vb
@@ -0,0 +1,18 @@
+Option Explicit On
+Option Strict On
+Option Infer On
+
+Imports CSV
+
+Friend Class UseCsvGenerator
+
+ Public Shared Sub Run()
+
+ Console.WriteLine("## CARS")
+ Cars.All.ToList().ForEach(Sub(c) Console.WriteLine(c.Brand & vbTab & c.Model & vbTab & c.Year & vbTab & c.Cc & vbTab & c.Favorite))
+ Console.WriteLine(vbCr & "## PEOPLE")
+ People.All.ToList().ForEach(Sub(p) Console.WriteLine(p.Name & vbTab & p.Address & vbTab & p._11Age))
+
+ End Sub
+
+End Class
diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseHelloWorldGenerator.vb b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseHelloWorldGenerator.vb
new file mode 100644
index 000000000..89fa11b47
--- /dev/null
+++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseHelloWorldGenerator.vb
@@ -0,0 +1,8 @@
+Public Module UseHelloWorldGenerator
+
+ Public Sub Run()
+ ' The static call below is generated at build time, and will list the syntax trees used in the compilation
+ HelloWorldGenerated.HelloWorld.SayHello()
+ End Sub
+
+End Module
diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseXmlSettingsGenerator.vb b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseXmlSettingsGenerator.vb
new file mode 100644
index 000000000..eb9a8e730
--- /dev/null
+++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/UseXmlSettingsGenerator.vb
@@ -0,0 +1,25 @@
+Imports AutoSettings
+
+Public Module UseXmlSettingsGenerator
+
+ Public Sub Run()
+
+ ' This XmlSettings generator makes a static property in the XmlSettings class for each .xmlsettings file
+
+ ' here we have the 'Main' settings file from MainSettings.xmlsettings
+ ' the name is determined by the 'name' attribute of the root settings element
+ Dim main As XmlSettings.MainSettings = XmlSettings.Main
+ Console.WriteLine($"Reading settings from {main.GetLocation()}")
+
+ ' settings are strongly typed and can be read directly from the static instance
+ Dim firstRun As Boolean = XmlSettings.Main.FirstRun
+ Console.WriteLine($"Setting firstRun = {firstRun}")
+
+ Dim cacheSize As Integer = XmlSettings.Main.CacheSize
+ Console.WriteLine($"Setting cacheSize = {cacheSize}")
+
+ ' Try adding some keys to the settings file and see the settings become available to read from
+
+ End Sub
+
+End Module
diff --git a/samples/VisualBasic/SourceGenerators/GeneratedDemo/VisualBasicGeneratedDemo.vbproj b/samples/VisualBasic/SourceGenerators/GeneratedDemo/VisualBasicGeneratedDemo.vbproj
new file mode 100644
index 000000000..6df6a390c
--- /dev/null
+++ b/samples/VisualBasic/SourceGenerators/GeneratedDemo/VisualBasicGeneratedDemo.vbproj
@@ -0,0 +1,23 @@
+
+
+
+ Exe
+ netcoreapp3.1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/VisualBasic/SourceGenerators/README.md b/samples/VisualBasic/SourceGenerators/README.md
new file mode 100644
index 000000000..63d0029eb
--- /dev/null
+++ b/samples/VisualBasic/SourceGenerators/README.md
@@ -0,0 +1,35 @@
+🚧 Work In Progress
+========
+
+These samples are for an in-progress feature of Roslyn. As such they may change or break as the feature is developed, and no level of support is implied.
+
+For more information on the Source Generators feature, see the [design document](https://github.com/dotnet/roslyn/blob/master/docs/features/source-generators.md).
+
+Prerequisites
+-----
+
+These samples require **Visual Studio 16.9.0 Preview 2.0** or higher.
+
+Building the samples
+-----
+Open `SourceGenerators.sln` in Visual Studio or run `dotnet build` from the `\SourceGenerators` directory.
+
+Running the samples
+-----
+
+The generators must be run as part of another build, as they inject source into the project being built. This repo contains a sample project `GeneratorDemo` that relies of the sample generators to add code to it's compilation.
+
+Run `GeneratedDemo` in Visual studio or run `dotnet run` from the `GeneratorDemo` directory.
+
+Using the samples in your project
+-----
+
+You can add the sample generators to your own project by adding an item group containing an analyzer reference:
+
+```xml
+
+
+
+```
+
+You will most likely need to close and reopen the solution in Visual Studio for any changes made to the generators to take effect.
diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.vb b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.vb
new file mode 100644
index 000000000..4c1ca4af8
--- /dev/null
+++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/AutoNotifyGenerator.vb
@@ -0,0 +1,201 @@
+Option Explicit On
+Option Infer On
+Option Strict On
+
+Imports System.Text
+
+Imports Microsoft.CodeAnalysis
+Imports Microsoft.CodeAnalysis.Text
+Imports Microsoft.CodeAnalysis.VisualBasic
+Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
+
+Namespace SourceGeneratorSamples
+
+
+ Public Class AutoNotifyGenerator
+ Implements ISourceGenerator
+
+ Private Const ATTRIBUTE_TEXT As String = "
+Imports System
+
+Namespace Global.AutoNotify
+
+ Friend NotInheritable Class AutoNotifyAttribute
+ Inherits Attribute
+
+ Public Sub New()
+ End Sub
+
+ Public Property PropertyName As String
+ End Class
+End Namespace
+"
+
+ Public Sub Initialize(context As GeneratorInitializationContext) Implements ISourceGenerator.Initialize
+ ' Register a syntax receiver that will be created for each generation pass
+ context.RegisterForSyntaxNotifications(Function() As ISyntaxReceiver
+ Return New SyntaxReceiver
+ End Function)
+ End Sub
+
+ Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute
+
+ ' add the attribute text
+ context.AddSource("AutoNotifyAttribute", SourceText.From(ATTRIBUTE_TEXT, Encoding.UTF8))
+
+ ' retreive the populated receiver
+ Dim tempVar = TypeOf context.SyntaxReceiver Is SyntaxReceiver
+ Dim receiver = TryCast(context.SyntaxReceiver, SyntaxReceiver)
+ If Not tempVar Then
+ Return
+ End If
+
+ ' we're going to create a new compilation that contains the attribute.
+ ' TODO: we should allow source generators to provide source during initialize, so that this step isn't required.
+ Dim options1 = context.Compilation.SyntaxTrees.First().Options
+ Dim compilation1 = context.Compilation.AddSyntaxTrees(VisualBasicSyntaxTree.ParseText(SourceText.From(ATTRIBUTE_TEXT, Encoding.UTF8), CType(options1, VisualBasicParseOptions)))
+
+ ' get the newly bound attribute, and INotifyPropertyChanged
+ Dim attributeSymbol = compilation1.GetTypeByMetadataName("AutoNotify.AutoNotifyAttribute")
+ Dim notifySymbol = compilation1.GetTypeByMetadataName("System.ComponentModel.INotifyPropertyChanged")
+
+ ' loop over the candidate fields, and keep the ones that are actually annotated
+ Dim fieldSymbols As New List(Of IFieldSymbol)
+
+ For Each field In receiver.CandidateFields
+ Dim model = compilation1.GetSemanticModel(field.SyntaxTree)
+ For Each variable In field.Declarators
+ For Each name In variable.Names
+ ' Get the symbol being decleared by the field, and keep it if its annotated
+ Dim fieldSymbol = TryCast(model.GetDeclaredSymbol(name), IFieldSymbol)
+ If fieldSymbol.GetAttributes().Any(Function(ad) ad.AttributeClass.Equals(attributeSymbol, SymbolEqualityComparer.[Default])) Then
+ fieldSymbols.Add(fieldSymbol)
+ End If
+ Next
+ Next
+ Next
+
+ ' group the fields by class, and generate the source
+ For Each group In fieldSymbols.GroupBy(Function(f) f.ContainingType, SymbolEqualityComparer.Default)
+ Dim classSource = ProcessClass(CType(group.Key, INamedTypeSymbol), group.ToList(), attributeSymbol, notifySymbol)
+ context.AddSource($"{group.Key.Name}_AutoNotify.vb", SourceText.From(classSource, Encoding.UTF8))
+ Next
+
+ End Sub
+
+ Private Function ProcessClass(classSymbol As INamedTypeSymbol, fields As List(Of IFieldSymbol), attributeSymbol As ISymbol, notifySymbol As ISymbol) As String
+
+ If Not classSymbol.ContainingSymbol.Equals(classSymbol.ContainingNamespace, SymbolEqualityComparer.[Default]) Then
+ Return Nothing 'TODO: issue a diagnostic that it must be top level
+ End If
+
+ Dim namespaceName = classSymbol.ContainingNamespace.ToDisplayString()
+
+ ' begin building the generated source
+ Dim source = New StringBuilder($"Option Explicit On
+Option Strict On
+Option Infer On
+
+Namespace Global.{namespaceName}
+
+ Partial Public Class {classSymbol.Name}
+ Implements {notifySymbol.ToDisplayString()}
+
+")
+
+ ' if the class doesn't implement INotifyPropertyChanged already, add it
+ If Not classSymbol.Interfaces.Contains(CType(notifySymbol, INamedTypeSymbol)) Then
+ source.Append(" Public Event PropertyChanged As System.ComponentModel.PropertyChangedEventHandler Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
+")
+ End If
+
+ ' create properties for each field
+ For Each fieldSymbol In fields
+ ProcessField(source, fieldSymbol, attributeSymbol)
+ Next
+
+ source.Append("
+ End Class
+
+End Namespace")
+
+ Return source.ToString()
+
+ End Function
+
+ Private Sub ProcessField(source As StringBuilder, fieldSymbol As IFieldSymbol, attributeSymbol As ISymbol)
+
+ Dim chooseName As Func(Of String, TypedConstant, String) =
+ Function(fieldName1 As String, overridenNameOpt1 As TypedConstant) As String
+
+ If Not overridenNameOpt1.IsNull Then
+ Return overridenNameOpt1.Value.ToString()
+ End If
+
+ fieldName1 = fieldName1.TrimStart("_"c)
+ If fieldName1.Length = 0 Then
+ Return String.Empty
+ End If
+
+ If fieldName1.Length = 1 Then
+ Return fieldName1.ToUpper()
+ End If
+
+ Return fieldName1.Substring(0, 1).ToUpper() & fieldName1.Substring(1)
+
+ End Function
+
+ ' get the name and type of the field
+ Dim fieldName = fieldSymbol.Name
+ Dim fieldType = fieldSymbol.Type
+
+ ' get the AutoNotify attribute from the field, and any associated data
+ Dim attributeData = fieldSymbol.GetAttributes().[Single](Function(ad) ad.AttributeClass.Equals(attributeSymbol, SymbolEqualityComparer.[Default]))
+ Dim overridenNameOpt = attributeData.NamedArguments.SingleOrDefault(Function(kvp) kvp.Key = "PropertyName").Value
+
+ Dim propertyName = chooseName(fieldName, overridenNameOpt)
+ If propertyName.Length = 0 OrElse propertyName = fieldName Then
+ 'TODO: issue a diagnostic that we can't process this field
+ Return
+ End If
+
+ source.Append($"
+ Public Property {propertyName} As {fieldType}
+ Get
+ Return Me.{fieldName}
+ End Get
+ Set(value As {fieldType})
+ Me.{fieldName} = value
+ RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs(NameOf({propertyName})))
+ End Set
+ End Property
+")
+
+ End Sub
+
+ '''
+ ''' Created on demand before each generation pass
+ '''
+ Class SyntaxReceiver
+ Implements ISyntaxReceiver
+
+ Public ReadOnly Property CandidateFields As List(Of FieldDeclarationSyntax) = New List(Of FieldDeclarationSyntax)
+
+ '''
+ ''' Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation
+ '''
+ Public Sub OnVisitSyntaxNode(syntaxNode As SyntaxNode) Implements ISyntaxReceiver.OnVisitSyntaxNode
+ ' any field with at least one attribute is a candidate for property generation
+ If TypeOf syntaxNode Is FieldDeclarationSyntax Then
+ Dim fieldDeclarationSyntax = TryCast(syntaxNode, FieldDeclarationSyntax)
+ If fieldDeclarationSyntax.AttributeLists.Count > 0 Then
+ CandidateFields.Add(fieldDeclarationSyntax)
+ End If
+ End If
+ End Sub
+
+ End Class
+
+ End Class
+
+End Namespace
diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/CsvGenerator.props b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/CsvGenerator.props
new file mode 100644
index 000000000..0741032bb
--- /dev/null
+++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/CsvGenerator.props
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/CsvGenerator.vb b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/CsvGenerator.vb
new file mode 100644
index 000000000..fa7d13b90
--- /dev/null
+++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/CsvGenerator.vb
@@ -0,0 +1,208 @@
+Option Explicit On
+Option Infer On
+Option Strict On
+
+Imports System.IO
+Imports System.Text
+
+Imports Microsoft.CodeAnalysis
+Imports Microsoft.CodeAnalysis.Text
+
+Imports NotVisualBasic.FileIO
+
+' CsvTextFileParser from https://github.com/22222/CsvTextFieldParser adding suppression rules for default VS config
+
+Namespace SourceGeneratorSamples
+
+
+ Public Class CsvGenerator
+ Implements ISourceGenerator
+
+ Public Enum CsvLoadType
+ Startup
+ OnDemand
+ End Enum
+
+ Public Sub Initialize(context As GeneratorInitializationContext) Implements Microsoft.CodeAnalysis.ISourceGenerator.Initialize
+
+ End Sub
+
+ Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute
+ Dim options As IEnumerable(Of (CsvLoadType, Boolean, AdditionalText)) = GetLoadOptions(context)
+ Dim nameCodeSequence As IEnumerable(Of (Name As String, Code As String)) = SourceFilesFromAdditionalFiles(options)
+ For Each entry In nameCodeSequence
+ context.AddSource($"Csv_{entry.Name}", SourceText.From(entry.Code, Encoding.UTF8))
+ Next
+ End Sub
+
+ ' Guesses type of property for the object from the value of a csv field
+ Public Shared Function GetCsvFieldType(exemplar As String) As String
+ Dim garbageBoolean As Boolean
+ Dim garbageInteger As Integer
+ Dim garbageDouble As Double
+ Select Case True
+ Case Boolean.TryParse(exemplar, garbageBoolean) : Return "Boolean"
+ Case Integer.TryParse(exemplar, garbageInteger) : Return "Integer"
+ Case Double.TryParse(exemplar, garbageDouble) : Return "Double"
+ Case Else : Return "String"
+ End Select
+ End Function
+
+ ' Examines the header row and the first row in the csv file to gather all header types and names
+ ' Also it returns the first row of data, because it must be read to figure out the types,
+ ' As the CsvTextFieldParser cannot 'Peek' ahead of one line. If there is no first line,
+ ' it consider all properties as strings. The generator returns an empty list of properly
+ ' typed objects in such case. If the file is completely empty, an error is generated.
+ Public Shared Function ExtractProperties(parser As CsvTextFieldParser) As (Types As String(), Names As String(), Fields As String())
+
+ Dim headerFields = parser.ReadFields()
+ If headerFields Is Nothing Then
+ Throw New Exception("Empty csv file!")
+ End If
+
+ Dim firstLineFields = parser.ReadFields()
+ If firstLineFields Is Nothing Then
+ Return (Enumerable.Repeat("String", headerFields.Length).ToArray(), headerFields, firstLineFields)
+ Else
+ Return (firstLineFields.[Select](Function(field) GetCsvFieldType(field)).ToArray(), headerFields.[Select](New Func(Of String, String)(AddressOf StringToValidPropertyName)).ToArray(), firstLineFields)
+ End If
+
+ End Function
+
+ ' Adds a class to the `CSV` namespace for each `csv` file passed in. The class has a static property
+ ' named `All` that returns the list of strongly typed objects generated on demand at first access.
+ ' There is the slight chance of a race condition in a multi-thread program, but the result is relatively benign
+ ' , loading the collection multiple times instead of once. Measures could be taken to avoid that.
+ Public Shared Function GenerateClassFile(className As String, csvText As String, loadTime As CsvLoadType, cacheObjects As Boolean) As String
+
+ Dim sb As New StringBuilder
+ Dim parser As New CsvTextFieldParser(New StringReader(csvText))
+
+ ''' Imports
+ sb.Append("Option Explicit On
+Option Strict On
+Option Infer On
+
+Imports System.Collections.Generic
+
+Namespace Global.CSV
+")
+
+ ''' Class Definition
+ sb.Append($"
+ Public Class {className}
+
+")
+
+ If loadTime = CsvLoadType.Startup Then
+ sb.Append($" Shared Sub New()
+ Dim x = All
+ End Sub
+
+")
+ End If
+
+ Dim tupleTemp = ExtractProperties(parser) : Dim types = tupleTemp.Types, names = tupleTemp.Names, fields = tupleTemp.Fields
+ Dim minLen = Math.Min(types.Length, names.Length)
+
+ For i = 0 To minLen - 1
+ sb.AppendLine($" Public Property {StringToValidPropertyName(names(i))} As {types(i)}")
+ Next
+
+ ''' Loading data
+ sb.Append($"
+ Private Shared m_all As IEnumerable(Of {className})
+
+ Public Shared ReadOnly Property All As IEnumerable(Of {className})
+ Get
+")
+
+ If cacheObjects Then
+ sb.Append(" If m_all IsNot Nothing Then
+ Return m_all
+ End If
+")
+ End If
+
+ sb.Append($" Dim l As New List(Of {className})()
+ Dim c As {className}
+")
+
+ Do
+
+ If fields Is Nothing Then
+ Continue Do
+ End If
+ If fields.Length < minLen Then
+ Throw New Exception("Not enough fields in CSV file.")
+ End If
+
+ sb.AppendLine($" c = New {className}()")
+
+ Dim value As String '= ""
+ For i As Integer = 0 To minLen - 1
+ ' Wrap strings in quotes.
+ value = If(GetCsvFieldType(fields(i)) = "String", $"""{fields(i).Trim().Trim(New Char() {""""c})}""", fields(i))
+ sb.AppendLine($" c.{names(i)} = {value}")
+ Next
+
+ sb.AppendLine(" l.Add(c)")
+
+ fields = parser.ReadFields()
+
+ Loop While fields IsNot Nothing
+
+ sb.Append($" m_all = l
+ Return l
+")
+
+ ' Close things (property, class, namespace)
+ sb.Append(" End Get
+ End Property
+
+ End Class
+
+End Namespace")
+
+ Return sb.ToString()
+
+ End Function
+
+ Private Shared Function StringToValidPropertyName(s As String) As String
+ s = s.Trim()
+ s = If(Char.IsLetter(s(0)), Char.ToUpper(s(0)) & s.Substring(1), s)
+ s = If(Char.IsDigit(s.Trim()(0)), "_" & s, s)
+ s = New String(s.[Select](Function(ch) If(Char.IsDigit(ch) OrElse Char.IsLetter(ch), ch, "_"c)).ToArray())
+ Return s
+ End Function
+
+ Private Shared Function SourceFilesFromAdditionalFile(loadType As CsvLoadType, cacheObjects As Boolean, file As AdditionalText) As IEnumerable(Of (Name As String, Code As String))
+ Dim className = Path.GetFileNameWithoutExtension(file.Path)
+ Dim csvText = file.GetText().ToString()
+ Return New(String, String)() {(className, GenerateClassFile(className, csvText, loadType, cacheObjects))}
+ End Function
+
+ Private Shared Function SourceFilesFromAdditionalFiles(pathsData As IEnumerable(Of (LoadType As CsvLoadType, CacheObjects As Boolean, File As AdditionalText))) As IEnumerable(Of (Name As String, Code As String))
+ Return pathsData.SelectMany(Function(d) SourceFilesFromAdditionalFile(d.LoadType, d.CacheObjects, d.File))
+ End Function
+
+ Private Shared Iterator Function GetLoadOptions(context As GeneratorExecutionContext) As IEnumerable(Of (LoadType As CsvLoadType, CacheObjects As Boolean, File As AdditionalText))
+ For Each file In context.AdditionalFiles
+ If Path.GetExtension(file.Path).Equals(".csv", StringComparison.OrdinalIgnoreCase) Then
+ ' are there any options for it?
+ Dim loadTimeString As String = Nothing
+ context.AnalyzerConfigOptions.GetOptions(file).TryGetValue("build_metadata.additionalfiles.CsvLoadType", loadTimeString)
+ Dim loadType As CsvLoadType = Nothing
+ [Enum].TryParse(loadTimeString, ignoreCase:=True, loadType)
+ Dim cacheObjectsString As String = Nothing
+ context.AnalyzerConfigOptions.GetOptions(file).TryGetValue("build_metadata.additionalfiles.CacheObjects", cacheObjectsString)
+ Dim cacheObjects As Boolean = Nothing
+ Boolean.TryParse(cacheObjectsString, cacheObjects)
+ Yield (loadType, cacheObjects, file)
+ End If
+ Next
+ End Function
+
+ End Class
+
+End Namespace
diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/HelloWorldGenerator.vb b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/HelloWorldGenerator.vb
new file mode 100644
index 000000000..ff4c51ba2
--- /dev/null
+++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/HelloWorldGenerator.vb
@@ -0,0 +1,66 @@
+Option Explicit On
+Option Infer On
+Option Strict On
+
+Imports System.Text
+
+Imports Microsoft.CodeAnalysis
+Imports Microsoft.CodeAnalysis.Text
+
+Namespace SourceGeneratorSamples
+
+
+ Public Class HelloWorldGenerator
+ Implements ISourceGenerator
+
+ Public Sub Initialize(context As GeneratorInitializationContext) Implements ISourceGenerator.Initialize
+ ' No initialization required
+ End Sub
+
+ Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute
+
+ ' begin creating the source we'll inject into the users compilation
+
+ Dim sourceBuilder = New StringBuilder("Option Explicit On
+Option Strict On
+Option Infer On
+
+Namespace Global.HelloWorldGenerated
+
+ Public Module HelloWorld
+
+ Public Sub SayHello()
+
+ Console.WriteLine(""Hello from generated code!"")
+ Console.WriteLine(""The following syntax trees existed in the compilation that created this program:"")
+")
+
+ ' for testing... let's include a comment with the current date/time.
+ sourceBuilder.AppendLine($" ' Generated at {DateTime.Now}")
+
+ ' using the context, get a list of syntax trees in the users compilation
+ ' add the filepath of each tree to the class we're building
+
+ For Each tree In context.Compilation.SyntaxTrees
+ sourceBuilder.AppendLine($" Console.WriteLine("" - {tree.FilePath}"")")
+ Next
+
+ ' finish creating the source to inject
+
+ sourceBuilder.Append("
+
+ End Sub
+
+ End Module
+
+End Namespace")
+
+ ' inject the created source into the users compilation
+
+ context.AddSource("HelloWorldGenerated", SourceText.From(sourceBuilder.ToString(), Encoding.UTF8))
+
+ End Sub
+
+ End Class
+
+End Namespace
diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/SettingsXmlGenerator.vb b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/SettingsXmlGenerator.vb
new file mode 100644
index 000000000..d1ecd628f
--- /dev/null
+++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/SettingsXmlGenerator.vb
@@ -0,0 +1,102 @@
+Option Explicit On
+Option Infer On
+Option Strict On
+
+Imports System.IO
+Imports System.Text
+Imports System.Xml
+
+Imports Microsoft.CodeAnalysis
+Imports Microsoft.CodeAnalysis.Text
+
+Namespace SourceGeneratorSamples
+
+
+ Public Class SettingsXmlGenerator
+ Implements ISourceGenerator
+
+ Public Sub Initialize(context As GeneratorInitializationContext) Implements ISourceGenerator.Initialize
+
+ End Sub
+
+ Public Sub Execute(context As GeneratorExecutionContext) Implements ISourceGenerator.Execute
+ ' Using the context, get any additional files that end in .xmlsettings
+ For Each settingsFile In context.AdditionalFiles.Where(Function(at) at.Path.EndsWith(".xmlsettings"))
+ ProcessSettingsFile(settingsFile, context)
+ Next
+ End Sub
+
+ Private Sub ProcessSettingsFile(xmlFile As AdditionalText, context As GeneratorExecutionContext)
+
+ ' try and load the settings file
+ Dim xmlDoc As New XmlDocument
+ Dim text = xmlFile.GetText(context.CancellationToken).ToString()
+ Try
+ xmlDoc.LoadXml(text)
+ Catch
+ 'TODO: issue a diagnostic that says we couldn't parse it
+ Return
+ End Try
+
+ ' create a class in the XmlSetting class that represnts this entry, and a static field that contains a singleton instance.
+ Dim fileName = Path.GetFileName(xmlFile.Path)
+ Dim name = xmlDoc.DocumentElement.GetAttribute("name")
+
+ Dim sb = New StringBuilder($"Option Explicit On
+Option Strict On
+Option Infer On
+
+Imports System.Xml
+
+Namespace Global.AutoSettings
+
+ Partial Public Class XmlSettings
+
+ Public Shared ReadOnly Property {name} As {name}Settings = New {name}Settings(""{fileName}"")
+
+ Public Class {name}Settings
+
+ Private m_xmlDoc As New XmlDocument()
+
+ Private m_fileName As String
+
+ Friend Sub New(fileName As String)
+ m_fileName = fileName
+ m_xmlDoc.Load(m_fileName)
+ End Sub
+
+ Public Function GetLocation() As String
+ Return m_fileName
+ End Function")
+
+ For i = 0 To xmlDoc.DocumentElement.ChildNodes.Count - 1
+
+ Dim setting = CType(xmlDoc.DocumentElement.ChildNodes(i), XmlElement)
+ Dim settingName = setting.GetAttribute("name")
+ Dim settingType = setting.GetAttribute("type")
+
+ sb.Append($"
+
+ Public ReadOnly Property {settingName} As {settingType}
+ Get
+ Return DirectCast(Convert.ChangeType(DirectCast(m_xmlDoc.DocumentElement.ChildNodes({i}), XmlElement).InnerText, GetType({settingType})), {settingType})
+ End Get
+ End Property")
+
+ Next
+
+ sb.Append("
+
+ End Class
+
+ End Class
+
+End Namespace")
+
+ context.AddSource($"Settings_{name}", SourceText.From(sb.ToString(), Encoding.UTF8))
+
+ End Sub
+
+ End Class
+
+End Namespace
diff --git a/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/VisualBasicSourceGeneratorSamples.vbproj b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/VisualBasicSourceGeneratorSamples.vbproj
new file mode 100644
index 000000000..9e9f12565
--- /dev/null
+++ b/samples/VisualBasic/SourceGenerators/SourceGeneratorSamples/VisualBasicSourceGeneratorSamples.vbproj
@@ -0,0 +1,27 @@
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(GetTargetPathDependsOn);GetDependencyTargetPaths
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/VisualBasic/SourceGenerators/SourceGenerators.sln b/samples/VisualBasic/SourceGenerators/SourceGenerators.sln
new file mode 100644
index 000000000..6b7947985
--- /dev/null
+++ b/samples/VisualBasic/SourceGenerators/SourceGenerators.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30022.13
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "GeneratedDemo", "GeneratedDemo\GeneratedDemo.vbproj", "{08612C19-D039-44D1-9030-D192CEAF05BB}"
+EndProject
+Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "SourceGeneratorSamples", "SourceGeneratorSamples\SourceGeneratorSamples.vbproj", "{90BDB1C3-E353-448C-8A29-E5B2EF10670B}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {08612C19-D039-44D1-9030-D192CEAF05BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {08612C19-D039-44D1-9030-D192CEAF05BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {08612C19-D039-44D1-9030-D192CEAF05BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {08612C19-D039-44D1-9030-D192CEAF05BB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {90BDB1C3-E353-448C-8A29-E5B2EF10670B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {90BDB1C3-E353-448C-8A29-E5B2EF10670B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {90BDB1C3-E353-448C-8A29-E5B2EF10670B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {90BDB1C3-E353-448C-8A29-E5B2EF10670B}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {623C84B6-B8A4-4F29-8E68-4ED37D4529D5}
+ EndGlobalSection
+EndGlobal
diff --git a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/AnalyzerTest`1.cs b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/AnalyzerTest`1.cs
index 770326c4f..6410ab7e1 100644
--- a/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/AnalyzerTest`1.cs
+++ b/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/AnalyzerTest`1.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
@@ -165,12 +166,34 @@ public string TestCode
///
protected TimeSpan MatchDiagnosticsTimeout { get; set; } = TimeSpan.FromSeconds(2);
+ private readonly ConcurrentBag _workspaces = new ConcurrentBag();
+
///
/// Runs the test.
///
/// The that the operation will observe.
/// A representing the asynchronous operation.
- public virtual async Task RunAsync(CancellationToken cancellationToken = default)
+ public async Task RunAsync(CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ await RunImplAsync(cancellationToken);
+ }
+ finally
+ {
+ while (_workspaces.TryTake(out var workspace))
+ {
+ workspace.Dispose();
+ }
+ }
+ }
+
+ ///
+ /// Runs the test.
+ ///
+ /// The that the operation will observe.
+ /// A representing the asynchronous operation.
+ protected virtual async Task RunImplAsync(CancellationToken cancellationToken)
{
Verify.NotEmpty($"{nameof(TestState)}.{nameof(SolutionState.Sources)}", TestState.Sources);
@@ -319,19 +342,19 @@ private async Task VerifySuppressionDiagnosticsAsync(ImmutableArrayA collection of s describing the expected
/// diagnostics for the sources.
/// The verifier to use for test assertions.
- private void VerifyDiagnosticResults(IEnumerable actualResults, ImmutableArray analyzers, DiagnosticResult[] expectedResults, IVerifier verifier)
+ private void VerifyDiagnosticResults(IEnumerable<(Project project, Diagnostic diagnostic)> actualResults, ImmutableArray analyzers, DiagnosticResult[] expectedResults, IVerifier verifier)
{
var matchedDiagnostics = MatchDiagnostics(actualResults.ToArray(), expectedResults);
verifier.Equal(actualResults.Count(), matchedDiagnostics.Count(x => x.actual is object), $"{nameof(MatchDiagnostics)} failed to include all actual diagnostics in the result");
verifier.Equal(expectedResults.Length, matchedDiagnostics.Count(x => x.expected is object), $"{nameof(MatchDiagnostics)} failed to include all expected diagnostics in the result");
- actualResults = matchedDiagnostics.Select(x => x.actual).WhereNotNull();
+ actualResults = matchedDiagnostics.Select(x => x.actual).Where(x => x is { }).Select(x => x!.Value);
expectedResults = matchedDiagnostics.Where(x => x.expected is object).Select(x => x.expected.GetValueOrDefault()).ToArray();
var expectedCount = expectedResults.Length;
var actualCount = actualResults.Count();
- var diagnosticsOutput = actualResults.Any() ? FormatDiagnostics(analyzers, DefaultFilePath, actualResults.ToArray()) : " NONE.";
+ var diagnosticsOutput = actualResults.Any() ? FormatDiagnostics(analyzers, DefaultFilePath, actualResults.Select(result => result.diagnostic).ToArray()) : " NONE.";
var message = $"Mismatch between number of diagnostics returned, expected \"{expectedCount}\" actual \"{actualCount}\"\r\n\r\nDiagnostics:\r\n{diagnosticsOutput}\r\n";
verifier.Equal(expectedCount, actualCount, message);
@@ -342,51 +365,51 @@ private void VerifyDiagnosticResults(IEnumerable actualResults, Immu
if (!expected.HasLocation)
{
- message = FormatVerifierMessage(analyzers, actual, expected, "Expected a project diagnostic with no location:");
- verifier.Equal(Location.None, actual.Location, message);
+ message = FormatVerifierMessage(analyzers, actual.diagnostic, expected, "Expected a project diagnostic with no location:");
+ verifier.Equal(Location.None, actual.diagnostic.Location, message);
}
else
{
- VerifyDiagnosticLocation(analyzers, actual, expected, actual.Location, expected.Spans[0], verifier);
+ VerifyDiagnosticLocation(analyzers, actual.diagnostic, expected, actual.diagnostic.Location, expected.Spans[0], verifier);
if (!expected.Options.HasFlag(DiagnosticOptions.IgnoreAdditionalLocations))
{
- var additionalLocations = actual.AdditionalLocations.ToArray();
+ var additionalLocations = actual.diagnostic.AdditionalLocations.ToArray();
- message = FormatVerifierMessage(analyzers, actual, expected, $"Expected {expected.Spans.Length - 1} additional locations but got {additionalLocations.Length} for Diagnostic:");
+ message = FormatVerifierMessage(analyzers, actual.diagnostic, expected, $"Expected {expected.Spans.Length - 1} additional locations but got {additionalLocations.Length} for Diagnostic:");
verifier.Equal(expected.Spans.Length - 1, additionalLocations.Length, message);
for (var j = 0; j < additionalLocations.Length; ++j)
{
- VerifyDiagnosticLocation(analyzers, actual, expected, additionalLocations[j], expected.Spans[j + 1], verifier);
+ VerifyDiagnosticLocation(analyzers, actual.diagnostic, expected, additionalLocations[j], expected.Spans[j + 1], verifier);
}
}
}
- message = FormatVerifierMessage(analyzers, actual, expected, $"Expected diagnostic id to be \"{expected.Id}\" was \"{actual.Id}\"");
- verifier.Equal(expected.Id, actual.Id, message);
+ message = FormatVerifierMessage(analyzers, actual.diagnostic, expected, $"Expected diagnostic id to be \"{expected.Id}\" was \"{actual.diagnostic.Id}\"");
+ verifier.Equal(expected.Id, actual.diagnostic.Id, message);
if (!expected.Options.HasFlag(DiagnosticOptions.IgnoreSeverity))
{
- message = FormatVerifierMessage(analyzers, actual, expected, $"Expected diagnostic severity to be \"{expected.Severity}\" was \"{actual.Severity}\"");
- verifier.Equal(expected.Severity, actual.Severity, message);
+ message = FormatVerifierMessage(analyzers, actual.diagnostic, expected, $"Expected diagnostic severity to be \"{expected.Severity}\" was \"{actual.diagnostic.Severity}\"");
+ verifier.Equal(expected.Severity, actual.diagnostic.Severity, message);
}
if (expected.Message != null)
{
- message = FormatVerifierMessage(analyzers, actual, expected, $"Expected diagnostic message to be \"{expected.Message}\" was \"{actual.GetMessage()}\"");
- verifier.Equal(expected.Message, actual.GetMessage(), message);
+ message = FormatVerifierMessage(analyzers, actual.diagnostic, expected, $"Expected diagnostic message to be \"{expected.Message}\" was \"{actual.diagnostic.GetMessage()}\"");
+ verifier.Equal(expected.Message, actual.diagnostic.GetMessage(), message);
}
else if (expected.MessageArguments?.Length > 0)
{
- message = FormatVerifierMessage(analyzers, actual, expected, $"Expected diagnostic message arguments to match");
+ message = FormatVerifierMessage(analyzers, actual.diagnostic, expected, $"Expected diagnostic message arguments to match");
verifier.SequenceEqual(
expected.MessageArguments.Select(argument => argument?.ToString() ?? string.Empty),
- GetArguments(actual).Select(argument => argument?.ToString() ?? string.Empty),
+ GetArguments(actual.diagnostic).Select(argument => argument?.ToString() ?? string.Empty),
StringComparer.Ordinal,
message);
}
- DiagnosticVerifier?.Invoke(actual, expected, verifier);
+ DiagnosticVerifier?.Invoke(actual.diagnostic, expected, verifier);
}
}
@@ -418,11 +441,11 @@ private void VerifyDiagnosticResults(IEnumerable actualResults, Immu
/// the total number of mismatched pairs.
///
///
- private ImmutableArray<(Diagnostic? actual, DiagnosticResult? expected)> MatchDiagnostics(Diagnostic[] actualResults, DiagnosticResult[] expectedResults)
+ private ImmutableArray<((Project project, Diagnostic diagnostic)? actual, DiagnosticResult? expected)> MatchDiagnostics((Project project, Diagnostic diagnostic)[] actualResults, DiagnosticResult[] expectedResults)
{
- var actualIds = actualResults.Select(result => result.Id).ToImmutableArray();
- var actualResultLocations = actualResults.Select(result => (location: result.Location.GetLineSpan(), additionalLocations: result.AdditionalLocations.Select(location => location.GetLineSpan()).ToImmutableArray())).ToImmutableArray();
- var actualArguments = actualResults.Select(actual => GetArguments(actual).Select(argument => argument?.ToString() ?? string.Empty).ToImmutableArray()).ToImmutableArray();
+ var actualIds = actualResults.Select(result => result.diagnostic.Id).ToImmutableArray();
+ var actualResultLocations = actualResults.Select(result => (location: result.diagnostic.Location.GetLineSpan(), additionalLocations: result.diagnostic.AdditionalLocations.Select(location => location.GetLineSpan()).ToImmutableArray())).ToImmutableArray();
+ var actualArguments = actualResults.Select(actual => GetArguments(actual.diagnostic).Select(argument => argument?.ToString() ?? string.Empty).ToImmutableArray()).ToImmutableArray();
expectedResults = expectedResults.ToOrderedArray();
var expectedArguments = expectedResults.Select(expected => expected.MessageArguments?.Select(argument => argument?.ToString() ?? string.Empty).ToImmutableArray() ?? ImmutableArray.Empty).ToImmutableArray();
@@ -430,9 +453,9 @@ private void VerifyDiagnosticResults(IEnumerable actualResults, Immu
// Initialize the best match to a trivial result where everything is unmatched. This will be updated if/when
// better matches are found.
var bestMatchCount = MatchQuality.RemainingUnmatched(actualResults.Length + expectedResults.Length);
- var bestMatch = actualResults.Select(result => ((Diagnostic?)result, default(DiagnosticResult?))).Concat(expectedResults.Select(result => (default(Diagnostic?), (DiagnosticResult?)result))).ToImmutableArray();
+ var bestMatch = actualResults.Select(result => (((Project project, Diagnostic diagnostic)?)result, default(DiagnosticResult?))).Concat(expectedResults.Select(result => (default((Project project, Diagnostic diagnostic)?), (DiagnosticResult?)result))).ToImmutableArray();
- var builder = ImmutableArray.CreateBuilder<(Diagnostic? actual, DiagnosticResult? expected)>();
+ var builder = ImmutableArray.CreateBuilder<((Project project, Diagnostic diagnostic)? actual, DiagnosticResult? expected)>();
var usedExpected = new bool[expectedResults.Length];
// The recursive match algorithm is not optimized, so use a timeout to ensure it completes in a reasonable
@@ -508,7 +531,7 @@ MatchQuality RecursiveMatch(int firstActualIndex, int remainingActualItems, int
}
var (lineSpan, additionalLineSpans) = actualResultLocations[firstActualIndex];
- var matchValue = GetMatchValue(actualResults[firstActualIndex], actualIds[firstActualIndex], lineSpan, additionalLineSpans, actualArguments[firstActualIndex], expectedResults[i], expectedArguments[i]);
+ var matchValue = GetMatchValue(actualResults[firstActualIndex].diagnostic, actualIds[firstActualIndex], lineSpan, additionalLineSpans, actualArguments[firstActualIndex], expectedResults[i], expectedArguments[i]);
if (matchValue == MatchQuality.None)
{
continue;
@@ -969,13 +992,15 @@ private static bool IsInSourceFile(DiagnosticResult result, (string filename, So
/// The that the task will observe.
/// A collection of s that surfaced in the source code, sorted by
/// .
- private async Task> GetSortedDiagnosticsAsync(EvaluatedProjectState primaryProject, ImmutableArray additionalProjects, ImmutableArray analyzers, IVerifier verifier, CancellationToken cancellationToken)
+ private async Task> GetSortedDiagnosticsAsync(EvaluatedProjectState primaryProject, ImmutableArray additionalProjects, ImmutableArray analyzers, IVerifier verifier, CancellationToken cancellationToken)
{
var solution = await GetSolutionAsync(primaryProject, additionalProjects, verifier, cancellationToken);
- var additionalDiagnostics = primaryProject.AdditionalDiagnostics;
- foreach (var project in additionalProjects)
+ var primaryProjectInSolution = solution.Projects.Single(project => project.Name == DefaultTestProjectName);
+ var additionalDiagnostics = primaryProject.AdditionalDiagnostics.Select(diagnostic => (primaryProjectInSolution, diagnostic)).ToImmutableArray();
+ foreach (var additionalProject in additionalProjects)
{
- additionalDiagnostics = additionalDiagnostics.AddRange(project.AdditionalDiagnostics);
+ var additionalProjectInSolution = solution.Projects.Single(project => project.Name == additionalProject.Name);
+ additionalDiagnostics = additionalDiagnostics.AddRange(additionalProject.AdditionalDiagnostics.Select(diagnostic => (additionalProjectInSolution, diagnostic)));
}
return await GetSortedDiagnosticsAsync(solution, analyzers, additionalDiagnostics, CompilerDiagnostics, verifier, cancellationToken);
@@ -993,21 +1018,21 @@ private async Task> GetSortedDiagnosticsAsync(Evaluat
/// The that the task will observe.
/// A collection of s that surfaced in the source code, sorted by
/// .
- protected async Task> GetSortedDiagnosticsAsync(Solution solution, ImmutableArray analyzers, ImmutableArray additionalDiagnostics, CompilerDiagnostics compilerDiagnostics, IVerifier verifier, CancellationToken cancellationToken)
+ protected async Task> GetSortedDiagnosticsAsync(Solution solution, ImmutableArray analyzers, ImmutableArray<(Project project, Diagnostic diagnostic)> additionalDiagnostics, CompilerDiagnostics compilerDiagnostics, IVerifier verifier, CancellationToken cancellationToken)
{
if (analyzers.IsEmpty)
{
analyzers = ImmutableArray.Create(new EmptyDiagnosticAnalyzer());
}
- var diagnostics = ImmutableArray.CreateBuilder();
+ var diagnostics = ImmutableArray.CreateBuilder<(Project project, Diagnostic diagnostic)>();
foreach (var project in solution.Projects)
{
var compilation = await GetProjectCompilationAsync(project, verifier, cancellationToken).ConfigureAwait(false);
var compilationWithAnalyzers = compilation.WithAnalyzers(analyzers, GetAnalyzerOptions(project), cancellationToken);
var allDiagnostics = await compilationWithAnalyzers.GetAllDiagnosticsAsync().ConfigureAwait(false);
- diagnostics.AddRange(allDiagnostics.Where(diagnostic => !IsCompilerDiagnostic(diagnostic) || IsCompilerDiagnosticIncluded(diagnostic, compilerDiagnostics)));
+ diagnostics.AddRange(allDiagnostics.Where(diagnostic => !IsCompilerDiagnostic(diagnostic) || IsCompilerDiagnosticIncluded(diagnostic, compilerDiagnostics)).Select(diagnostic => (project, diagnostic)));
}
diagnostics.AddRange(additionalDiagnostics);
@@ -1310,7 +1335,14 @@ protected virtual Project ApplyCompilationOptions(Project project)
return solution.GetProject(project.Id);
}
- public virtual AdhocWorkspace CreateWorkspace()
+ public Workspace CreateWorkspace()
+ {
+ var workspace = CreateWorkspaceImpl();
+ _workspaces.Add(workspace);
+ return workspace;
+ }
+
+ protected virtual Workspace CreateWorkspaceImpl()
{
var exportProvider = ExportProviderFactory.Value.CreateExportProvider();
var host = MefHostServices.Create(exportProvider.AsCompositionContext());
@@ -1327,14 +1359,14 @@ public virtual AdhocWorkspace CreateWorkspace()
/// A collection of s to be sorted.
/// A collection containing the input , sorted by
/// and .
- private static Diagnostic[] SortDistinctDiagnostics(IEnumerable diagnostics)
+ private static (Project project, Diagnostic diagnostic)[] SortDistinctDiagnostics(IEnumerable<(Project project, Diagnostic diagnostic)> diagnostics)
{
return diagnostics
- .OrderBy(d => d.Location.GetLineSpan().Path, StringComparer.Ordinal)
- .ThenBy(d => d.Location.SourceSpan.Start)
- .ThenBy(d => d.Location.SourceSpan.End)
- .ThenBy(d => d.Id)
- .ThenBy(d => GetArguments(d), LexicographicComparer.Instance).ToArray();
+ .OrderBy(d => d.diagnostic.Location.GetLineSpan().Path, StringComparer.Ordinal)
+ .ThenBy(d => d.diagnostic.Location.SourceSpan.Start)
+ .ThenBy(d => d.diagnostic.Location.SourceSpan.End)
+ .ThenBy(d => d.diagnostic.Id)
+ .ThenBy(d => GetArguments(d.diagnostic), LexicographicComparer.Instance).ToArray();
}
private static IReadOnlyList
+
+
+
+ Never
+ MSBuild:GenerateRuleSourceFromXaml
+ Designer
+ None
+ None
+
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/RuleExporter.cs b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/RuleExporter.cs
new file mode 100644
index 000000000..38382da9f
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/RuleExporter.cs
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.VisualStudio.ProjectSystem;
+using Microsoft.VisualStudio.ProjectSystem.Properties;
+
+namespace Roslyn.ComponentDebugger
+{
+ internal static class RuleExporter
+ {
+ ///
+ /// Used to export the XAML rule via MEF
+ ///
+ [ExportPropertyXamlRuleDefinition(
+ xamlResourceAssemblyName: "Roslyn.ComponentDebugger, Version=" + AssemblyVersion.Version + ", Culture=neutral, PublicKeyToken=31bf3856ad364e35",
+ xamlResourceStreamName: "XamlRuleToCode:ComponentDebuggerLaunchProfile.xaml",
+ context: PropertyPageContexts.Project)]
+ [AppliesTo(Constants.RoslynComponentCapability)]
+#pragma warning disable CS0649
+ public static int LaunchProfileRule;
+#pragma warning restore CS0649
+ }
+}
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/TargetProjectEnumProvider.cs b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/TargetProjectEnumProvider.cs
new file mode 100644
index 000000000..23582bd2a
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/TargetProjectEnumProvider.cs
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.ComponentModel.Composition;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Build.Framework.XamlTypes;
+using Microsoft.VisualStudio.ProjectSystem;
+using Microsoft.VisualStudio.ProjectSystem.Properties;
+
+namespace Roslyn.ComponentDebugger
+{
+ [ExportDynamicEnumValuesProvider(nameof(TargetProjectEnumProvider))]
+ [AppliesTo(Constants.RoslynComponentCapability)]
+ public class TargetProjectEnumProvider : IDynamicEnumValuesProvider
+ {
+ private readonly UnconfiguredProject _unconfiguredProject;
+ private readonly LaunchSettingsManager _launchSettingsManager;
+
+ [ImportingConstructor]
+ public TargetProjectEnumProvider(UnconfiguredProject unconfiguredProject, LaunchSettingsManager launchSettingsManager)
+ {
+ _unconfiguredProject = unconfiguredProject;
+ _launchSettingsManager = launchSettingsManager;
+ }
+
+ public async Task GetProviderAsync(IList? options)
+ {
+ // get the targets for this project
+ var projects = await _unconfiguredProject.GetComponentReferencingProjectsAsync().ConfigureAwait(false);
+
+ // convert to display values of friendly name + relative path
+ var displayValues = projects.Select(p => (Path.GetFileNameWithoutExtension(p.FullPath), _unconfiguredProject.MakeRelative(p.FullPath))).ToImmutableArray();
+
+ return new TargetProjectEnumValuesGenerator(displayValues);
+ }
+
+ private class TargetProjectEnumValuesGenerator : IDynamicEnumValuesGenerator
+ {
+ private readonly ImmutableArray<(string display, string path)> _referencingProjects;
+
+ public bool AllowCustomValues => false;
+
+ public TargetProjectEnumValuesGenerator(ImmutableArray<(string display, string path)> referencingProjects)
+ {
+ _referencingProjects = referencingProjects;
+ }
+
+ public Task> GetListedValuesAsync()
+ {
+ var values = _referencingProjects.Select(p => new PageEnumValue(new EnumValue() { DisplayName = p.display, Name = p.path})).Cast().ToImmutableArray();
+ return Task.FromResult>(values);
+ }
+
+ ///
+ /// The user can't add arbitrary projects from the UI, so this is unsupported
+ ///
+ public Task TryCreateEnumValueAsync(string userSuppliedValue) => Task.FromResult(null);
+ }
+ }
+}
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.cs.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.cs.xlf
new file mode 100644
index 000000000..70107d3d7
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.cs.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ A project that uses this component, whose compilation will be debugged.
+ A project that uses this component, whose compilation will be debugged.
+
+
+
+ Target Project
+ Target Project
+
+
+
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+
+
+
+ Roslyn Component
+ Roslyn Component
+
+
+
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.de.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.de.xlf
new file mode 100644
index 000000000..3f73ba68a
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.de.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ A project that uses this component, whose compilation will be debugged.
+ A project that uses this component, whose compilation will be debugged.
+
+
+
+ Target Project
+ Target Project
+
+
+
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+
+
+
+ Roslyn Component
+ Roslyn Component
+
+
+
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.es.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.es.xlf
new file mode 100644
index 000000000..49696eefb
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.es.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ A project that uses this component, whose compilation will be debugged.
+ A project that uses this component, whose compilation will be debugged.
+
+
+
+ Target Project
+ Target Project
+
+
+
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+
+
+
+ Roslyn Component
+ Roslyn Component
+
+
+
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.fr.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.fr.xlf
new file mode 100644
index 000000000..b0ad7e720
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.fr.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ A project that uses this component, whose compilation will be debugged.
+ A project that uses this component, whose compilation will be debugged.
+
+
+
+ Target Project
+ Target Project
+
+
+
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+
+
+
+ Roslyn Component
+ Roslyn Component
+
+
+
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.it.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.it.xlf
new file mode 100644
index 000000000..6e9993b18
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.it.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ A project that uses this component, whose compilation will be debugged.
+ A project that uses this component, whose compilation will be debugged.
+
+
+
+ Target Project
+ Target Project
+
+
+
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+
+
+
+ Roslyn Component
+ Roslyn Component
+
+
+
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ja.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ja.xlf
new file mode 100644
index 000000000..38b0fc455
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ja.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ A project that uses this component, whose compilation will be debugged.
+ A project that uses this component, whose compilation will be debugged.
+
+
+
+ Target Project
+ Target Project
+
+
+
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+
+
+
+ Roslyn Component
+ Roslyn Component
+
+
+
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ko.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ko.xlf
new file mode 100644
index 000000000..55caf820f
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ko.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ A project that uses this component, whose compilation will be debugged.
+ A project that uses this component, whose compilation will be debugged.
+
+
+
+ Target Project
+ Target Project
+
+
+
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+
+
+
+ Roslyn Component
+ Roslyn Component
+
+
+
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.pl.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.pl.xlf
new file mode 100644
index 000000000..d623a3953
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.pl.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ A project that uses this component, whose compilation will be debugged.
+ A project that uses this component, whose compilation will be debugged.
+
+
+
+ Target Project
+ Target Project
+
+
+
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+
+
+
+ Roslyn Component
+ Roslyn Component
+
+
+
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.pt-BR.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.pt-BR.xlf
new file mode 100644
index 000000000..d93d99696
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.pt-BR.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ A project that uses this component, whose compilation will be debugged.
+ A project that uses this component, whose compilation will be debugged.
+
+
+
+ Target Project
+ Target Project
+
+
+
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+
+
+
+ Roslyn Component
+ Roslyn Component
+
+
+
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ru.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ru.xlf
new file mode 100644
index 000000000..5890416c8
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.ru.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ A project that uses this component, whose compilation will be debugged.
+ A project that uses this component, whose compilation will be debugged.
+
+
+
+ Target Project
+ Target Project
+
+
+
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+
+
+
+ Roslyn Component
+ Roslyn Component
+
+
+
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.tr.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.tr.xlf
new file mode 100644
index 000000000..8c8db3e8f
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.tr.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ A project that uses this component, whose compilation will be debugged.
+ A project that uses this component, whose compilation will be debugged.
+
+
+
+ Target Project
+ Target Project
+
+
+
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+
+
+
+ Roslyn Component
+ Roslyn Component
+
+
+
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.zh-Hans.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.zh-Hans.xlf
new file mode 100644
index 000000000..1e3273ef3
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.zh-Hans.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ A project that uses this component, whose compilation will be debugged.
+ A project that uses this component, whose compilation will be debugged.
+
+
+
+ Target Project
+ Target Project
+
+
+
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+
+
+
+ Roslyn Component
+ Roslyn Component
+
+
+
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.zh-Hant.xlf b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.zh-Hant.xlf
new file mode 100644
index 000000000..5720b1a0c
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/xlf/ComponentDebuggerLaunchProfile.xaml.zh-Hant.xlf
@@ -0,0 +1,32 @@
+
+
+
+
+
+ A project that uses this component, whose compilation will be debugged.
+ A project that uses this component, whose compilation will be debugged.
+
+
+
+ Target Project
+ Target Project
+
+
+
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+ Allows a user to debug a Roslyn Component by running it in the context of another projects build.
+
+
+
+ Roslyn Component
+ Roslyn Component
+
+
+
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+ A Roslyn Component can be debugged in the context of compiling a second project that uses it. Ensure your target project is referencing this component for it to appear in the list.
+
+
+
+
+
\ No newline at end of file
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK.Template.Wizard/RoslynSDKRootTemplateWizard.cs b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK.Template.Wizard/RoslynSDKRootTemplateWizard.cs
index 9875b5f8d..a74df4b69 100644
--- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK.Template.Wizard/RoslynSDKRootTemplateWizard.cs
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK.Template.Wizard/RoslynSDKRootTemplateWizard.cs
@@ -9,19 +9,6 @@
public partial class RoslynSDKRootTemplateWizard
{
- private const string NuGetConfig = @"
-
-
-
-
-
-
-
-
-
-
-";
-
public static Dictionary GlobalDictionary = new Dictionary();
private void OnRunStarted(DTE dte, Dictionary replacementsDictionary, WizardRunKind runKind, object[] customParams)
@@ -31,22 +18,5 @@ private void OnRunStarted(DTE dte, Dictionary replacementsDictio
// add the root project name (the name the user passed in) to the global replacement dictionary
GlobalDictionary["$saferootprojectname$"] = replacementsDictionary["$safeprojectname$"];
GlobalDictionary["$saferootidentifiername$"] = replacementsDictionary["$safeprojectname$"].Replace(".","");
-
- if (!replacementsDictionary.TryGetValue("$solutiondirectory$", out var solutionFolder))
- {
- var solutionFile = dte.Solution.FullName;
- if (string.IsNullOrEmpty(solutionFile))
- return;
-
- solutionFolder = Path.GetDirectoryName(solutionFile);
- }
-
- if (Directory.Exists(solutionFolder))
- {
- File.WriteAllText(
- Path.Combine(solutionFolder, "NuGet.config"),
- NuGetConfig,
- Encoding.UTF8);
- }
}
}
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Test/Test.csproj b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Test/Test.csproj
index 9c07533da..3ff076d88 100644
--- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Test/Test.csproj
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/CSharp/Diagnostic/Test/Test.csproj
@@ -12,12 +12,12 @@
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Test/UnitTestProject.vbproj b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Test/UnitTestProject.vbproj
index 75b2bcd1f..570444648 100644
--- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Test/UnitTestProject.vbproj
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/ProjectTemplates/VisualBasic/Diagnostic/Test/UnitTestProject.vbproj
@@ -12,12 +12,12 @@
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Properties/AssemblyInfo.cs b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Properties/AssemblyInfo.cs
index 6ccb8544f..710a6f0cb 100644
--- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Properties/AssemblyInfo.cs
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Properties/AssemblyInfo.cs
@@ -5,3 +5,4 @@
using Microsoft.VisualStudio.Shell;
[assembly: ProvideBindingRedirection(CodeBase = "Roslyn.SDK.Template.Wizard.dll", OldVersionLowerBound = "1.0.0.0")]
+[assembly: ProvideCodeBase(AssemblyName = "Roslyn.ComponentDebugger", CodeBase = "$PackageFolder$\\Roslyn.ComponentDebugger.dll")]
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Roslyn.SDK.csproj b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Roslyn.SDK.csproj
index 4a2d50555..8f82ad750 100644
--- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Roslyn.SDK.csproj
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Roslyn.SDK.csproj
@@ -123,8 +123,8 @@
Roslyn.ComponentDebugger
- BuiltProjectOutputGroup%3bGetCopyToOutputDirectoryItems%3b
- DebugSymbolsProjectOutputGroup%3b
+ BuiltProjectOutputGroup%3bGetCopyToOutputDirectoryItems
+ DebugSymbolsProjectOutputGrouptruefalse
diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/MetadataReferenceTests.cs b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/MetadataReferenceTests.cs
index 70f0a47d5..9a5f501f3 100644
--- a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/MetadataReferenceTests.cs
+++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/MetadataReferenceTests.cs
@@ -450,6 +450,7 @@ public async Task ResolveReferenceAssemblies_Net50()
[InlineData("netcoreapp3.1")]
#if !(NETCOREAPP1_1 || NET46)
[InlineData("net5.0")]
+ [InlineData("net6.0")]
#endif
[InlineData("netstandard1.0")]
[InlineData("netstandard1.1")]
@@ -500,6 +501,7 @@ internal static ReferenceAssemblies ReferenceAssembliesForTargetFramework(string
"netcoreapp3.0" => ReferenceAssemblies.NetCore.NetCoreApp30,
"netcoreapp3.1" => ReferenceAssemblies.NetCore.NetCoreApp31,
"net5.0" => ReferenceAssemblies.Net.Net50,
+ "net6.0" => ReferenceAssemblies.Net.Net60,
"netstandard1.0" => ReferenceAssemblies.NetStandard.NetStandard10,
"netstandard1.1" => ReferenceAssemblies.NetStandard.NetStandard11,
"netstandard1.2" => ReferenceAssemblies.NetStandard.NetStandard12,
diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/MultipleProjectsTests.cs b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/MultipleProjectsTests.cs
index 0ecfcd1e9..118ba2b01 100644
--- a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/MultipleProjectsTests.cs
+++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/MultipleProjectsTests.cs
@@ -12,6 +12,8 @@
Microsoft.CodeAnalysis.Testing.TestAnalyzers.HighlightBracesAnalyzer,
Microsoft.CodeAnalysis.Testing.TestAnalyzers.CSharpAnalyzerTest,
Microsoft.CodeAnalysis.Testing.DefaultVerifier>;
+using VisualBasicTest = Microsoft.CodeAnalysis.Testing.TestAnalyzers.VisualBasicAnalyzerTest<
+ Microsoft.CodeAnalysis.Testing.TestAnalyzers.HighlightBracesAnalyzer>;
namespace Microsoft.CodeAnalysis.Testing
{
@@ -44,6 +46,87 @@ public async Task TwoCSharpProjects_Independent()
}.RunAsync();
}
+ [Fact]
+ public async Task TwoVisualBasicProjects_Independent()
+ {
+ await new VisualBasicTest
+ {
+ TestState =
+ {
+ Sources =
+ {
+ @"Public Class Derived1 : Inherits {|BC30002:Base2|} : End Class",
+ @"Public Class Base1 : End Class",
+ },
+ AdditionalProjects =
+ {
+ ["Secondary"] =
+ {
+ Sources =
+ {
+ @"Public Class Derived2 : Inherits {|BC30002:Base1|} : End Class",
+ @"Public Class Base2 : End Class",
+ },
+ },
+ },
+ },
+ }.RunAsync();
+ }
+
+ [Fact]
+ public async Task OneCSharpProjectOneVisualBasicProject_Independent()
+ {
+ await new CSharpTest
+ {
+ TestState =
+ {
+ Sources =
+ {
+ @"public class Derived1 : {|CS0246:Base2|} [|{|] }",
+ @"public class Base1 [|{|] }",
+ },
+ AdditionalProjects =
+ {
+ ["Secondary", LanguageNames.VisualBasic] =
+ {
+ Sources =
+ {
+ @"Public Class Derived2 : Inherits {|BC30002:Base1|} : End Class",
+ @"Public Class Base2 : End Class",
+ },
+ },
+ },
+ },
+ }.RunAsync();
+ }
+
+ [Fact]
+ public async Task OneVisualBasicProjectOneCSharpProject_Independent()
+ {
+ await new VisualBasicTest
+ {
+ TestState =
+ {
+ Sources =
+ {
+ @"Public Class Derived1 : Inherits {|BC30002:Base2|} : End Class",
+ @"Public Class Base1 : End Class",
+ },
+ AdditionalProjects =
+ {
+ ["Secondary", LanguageNames.CSharp] =
+ {
+ Sources =
+ {
+ @"public class Derived2 : {|CS0246:Base1|} [|{|] }",
+ @"public class Base2 [|{|] }",
+ },
+ },
+ },
+ },
+ }.RunAsync();
+ }
+
[Fact]
public async Task TwoCSharpProjects_IndependentWithMarkupLocations()
{
@@ -120,6 +203,93 @@ public async Task TwoCSharpProjects_PrimaryReferencesSecondary()
}.RunAsync();
}
+ [Fact]
+ public async Task TwoVisualBasicProjects_PrimaryReferencesSecondary()
+ {
+ // TestProject references Secondary
+ await new VisualBasicTest
+ {
+ TestState =
+ {
+ Sources =
+ {
+ @"Public Class Derived1 : Inherits Base2 : End Class",
+ @"Public Class Base1 : End Class",
+ },
+ AdditionalProjectReferences = { "Secondary", },
+ AdditionalProjects =
+ {
+ ["Secondary"] =
+ {
+ Sources =
+ {
+ @"Public Class Derived2 : Inherits {|BC30002:Base1|} : End Class",
+ @"Public Class Base2 : End Class",
+ },
+ },
+ },
+ },
+ }.RunAsync();
+ }
+
+ [Fact]
+ public async Task OneCSharpProjectOneVisualBasicProject_PrimaryReferencesSecondary()
+ {
+ // TestProject references Secondary
+ await new CSharpTest
+ {
+ TestState =
+ {
+ Sources =
+ {
+ @"public class Type1 [|{|] object field = new Type3(); }",
+ @"public class Type2 [|{|] }",
+ },
+ AdditionalProjectReferences = { "Secondary", },
+ AdditionalProjects =
+ {
+ ["Secondary", LanguageNames.VisualBasic] =
+ {
+ Sources =
+ {
+ @"Public Class Type3 : Private field As Object = New {|BC30002:Type1|}() : End Class",
+ @"Public Class Type4 : End Class",
+ },
+ },
+ },
+ },
+ }.RunAsync();
+ }
+
+ [Fact]
+ public async Task OneVisualBasicProjectOneCSharpProject_PrimaryReferencesSecondary()
+ {
+ // TestProject references Secondary
+ await new VisualBasicTest
+ {
+ TestState =
+ {
+ Sources =
+ {
+ @"Public Class Type1 : Private field As Object = New Type3() : End Class",
+ @"Public Class Type2 : End Class",
+ },
+ AdditionalProjectReferences = { "Secondary", },
+ AdditionalProjects =
+ {
+ ["Secondary", LanguageNames.CSharp] =
+ {
+ Sources =
+ {
+ @"public class Type3 [|{|] object field = new {|CS0246:Type1|}(); }",
+ @"public class Type4 [|{|] }",
+ },
+ },
+ },
+ },
+ }.RunAsync();
+ }
+
[Fact]
public async Task TwoCSharpProjects_SecondaryReferencesPrimary()
{
@@ -149,6 +319,93 @@ public async Task TwoCSharpProjects_SecondaryReferencesPrimary()
}.RunAsync();
}
+ [Fact]
+ public async Task TwoVisualBasicProjects_SecondaryReferencesPrimary()
+ {
+ // TestProject references Secondary
+ await new VisualBasicTest
+ {
+ TestState =
+ {
+ Sources =
+ {
+ @"Public Class Derived1 : Inherits {|BC30002:Base2|} : End Class",
+ @"Public Class Base1 : End Class",
+ },
+ AdditionalProjects =
+ {
+ ["Secondary"] =
+ {
+ Sources =
+ {
+ @"Public Class Derived2 : Inherits Base1 : End Class",
+ @"Public Class Base2 : End Class",
+ },
+ AdditionalProjectReferences = { "TestProject" },
+ },
+ },
+ },
+ }.RunAsync();
+ }
+
+ [Fact]
+ public async Task OneCSharpProjectOneVisualBasicProject_SecondaryReferencesPrimary()
+ {
+ // TestProject references Secondary
+ await new CSharpTest
+ {
+ TestState =
+ {
+ Sources =
+ {
+ @"public class Type1 [|{|] object field = new {|CS0246:Type3|}(); }",
+ @"public class Type2 [|{|] }",
+ },
+ AdditionalProjects =
+ {
+ ["Secondary", LanguageNames.VisualBasic] =
+ {
+ Sources =
+ {
+ @"Public Class Type3 : Private field As Object = New Type1() : End Class",
+ @"Public Class Type4 : End Class",
+ },
+ AdditionalProjectReferences = { "TestProject" },
+ },
+ },
+ },
+ }.RunAsync();
+ }
+
+ [Fact]
+ public async Task OneVisualBasicProjectOneCSharpProject_SecondaryReferencesPrimary()
+ {
+ // TestProject references Secondary
+ await new VisualBasicTest
+ {
+ TestState =
+ {
+ Sources =
+ {
+ @"Public Class Type1 : Private field As Object = New {|BC30002:Type3|}() : End Class",
+ @"Public Class Type2 : End Class",
+ },
+ AdditionalProjects =
+ {
+ ["Secondary", LanguageNames.CSharp] =
+ {
+ Sources =
+ {
+ @"public class Type3 [|{|] object field = new Type1(); }",
+ @"public class Type4 [|{|] }",
+ },
+ AdditionalProjectReferences = { "TestProject" },
+ },
+ },
+ },
+ }.RunAsync();
+ }
+
[Fact]
public async Task TwoCSharpProjects_DefaultPaths()
{
diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/VerifierExtensionsTests.cs b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/VerifierExtensionsTests.cs
new file mode 100644
index 000000000..eb850de69
--- /dev/null
+++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing.UnitTests/VerifierExtensionsTests.cs
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using Xunit;
+
+namespace Microsoft.CodeAnalysis.Testing
+{
+ public class VerifierExtensionsTests
+ {
+ [Fact]
+ [WorkItem(876, "https://github.com/dotnet/roslyn-sdk/issues/876")]
+ public void VerifyContentWithMixedLineEndings1()
+ {
+ var baseline =
+ "Line 1\r\n"
+ + "Line 2\r\n"
+ + "Line 3\r\n"
+ + "Line 4\r\n"
+ + "Line 5\r\n"
+ + "Line 6\r\n";
+ var modified =
+ "Line 1\r"
+ + "Line 2\r\n"
+ + "Line 3\n"
+ + "Line 4\r"
+ + "Line 5\r\n"
+ + "Line 6\n";
+
+ var exception = Assert.Throws(() => new DefaultVerifier().EqualOrDiff(baseline, modified));
+ Assert.Equal(
+ $"Actual and expected values differ. Expected shown in baseline of diff:{Environment.NewLine}"
+ + $"-Line 1{Environment.NewLine}"
+ + $"+Line 1{Environment.NewLine}"
+ + $" Line 2{Environment.NewLine}"
+ + $"-Line 3{Environment.NewLine}"
+ + $"-Line 4{Environment.NewLine}"
+ + $"+Line 3{Environment.NewLine}"
+ + $"+Line 4{Environment.NewLine}"
+ + $" Line 5{Environment.NewLine}"
+ + $"-Line 6{Environment.NewLine}"
+ + $"+Line 6{Environment.NewLine}",
+ exception.Message);
+ }
+
+ [Fact]
+ [WorkItem(876, "https://github.com/dotnet/roslyn-sdk/issues/876")]
+ public void VerifyContentWithMixedLineEnding2()
+ {
+ var baseline =
+ "Line 1\n"
+ + "Line 2\n"
+ + "Line 3\n"
+ + "Line 4\n"
+ + "Line 5\n"
+ + "Line 6\n";
+ var modified =
+ "Line 1\r"
+ + "Line 2\r\n"
+ + "Line 3\n"
+ + "Line 4\r"
+ + "Line 5\r\n"
+ + "Line 6\n";
+
+ var exception = Assert.Throws(() => new DefaultVerifier().EqualOrDiff(baseline, modified));
+ Assert.Equal(
+ $"Actual and expected values differ. Expected shown in baseline of diff:{Environment.NewLine}"
+ + $"-Line 1{Environment.NewLine}"
+ + $"-Line 2{Environment.NewLine}"
+ + $"+Line 1{Environment.NewLine}"
+ + $"+Line 2{Environment.NewLine}"
+ + $" Line 3{Environment.NewLine}"
+ + $"-Line 4{Environment.NewLine}"
+ + $"-Line 5{Environment.NewLine}"
+ + $"+Line 4{Environment.NewLine}"
+ + $"+Line 5{Environment.NewLine}"
+ + $" Line 6{Environment.NewLine}",
+ exception.Message);
+ }
+ }
+}
diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing.UnitTests/CodeFixIterationTests.cs b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing.UnitTests/CodeFixIterationTests.cs
index 43704cacf..e50674169 100644
--- a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing.UnitTests/CodeFixIterationTests.cs
+++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing.UnitTests/CodeFixIterationTests.cs
@@ -3,18 +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.Threading;
using System.Threading.Tasks;
-using Microsoft.CodeAnalysis.CodeActions;
-using Microsoft.CodeAnalysis.CodeFixes;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing.TestAnalyzers;
using Microsoft.CodeAnalysis.Testing.TestFixes;
-using Microsoft.CodeAnalysis.Text;
using Xunit;
namespace Microsoft.CodeAnalysis.Testing
@@ -220,11 +212,11 @@ class TestClass {
}.RunAsync();
});
- new DefaultVerifier().EqualOrDiff($"Context: Iterative code fix application{Environment.NewLine}The upper limit for the number of code fix iterations was exceeded", exception.Message);
+ new DefaultVerifier().EqualOrDiff($"Context: Iterative code fix application{Environment.NewLine}Expected '1' iterations but found '2' iterations.", exception.Message);
}
[Theory]
- [InlineData(-1, "The upper limit for the number of code fix iterations was exceeded", " 5")]
+ [InlineData(-1, "Expected '1' iterations but found '2' iterations.", " 5")]
[InlineData(0, "The upper limit for the number of code fix iterations was exceeded", " [|4|]")]
[InlineData(1, "Expected '1' iterations but found '2' iterations.", " 5")]
public async Task TestTwoIterationsRequiredButIncrementalDeclaredIncorrectly(int declaredIncrementalIterations, string message, string replacement)
@@ -284,11 +276,11 @@ class TestClass {
}.RunAsync();
});
- Assert.Equal($"Context: Fix all in document{Environment.NewLine}The upper limit for the number of code fix iterations was exceeded", exception.Message);
+ Assert.Equal($"Context: Fix all in document{Environment.NewLine}Expected '1' iterations but found '2' iterations.", exception.Message);
}
[Theory]
- [InlineData(-1, "The upper limit for the number of code fix iterations was exceeded", " 5")]
+ [InlineData(-1, "Expected '1' iterations but found '2' iterations.", " 5")]
[InlineData(0, "The upper limit for the number of fix all iterations was exceeded", " [|4|]")]
[InlineData(1, "Expected '1' iterations but found '2' iterations.", " 5")]
public async Task TestTwoIterationsRequiredButFixAllDeclaredIncorrectly(int declaredFixAllIterations, string message, string replacement)
@@ -403,67 +395,65 @@ class TestClass2 {
Assert.Equal($"Context: {context}{Environment.NewLine}Expected '2' iterations but found '1' iterations.", exception.Message);
}
- ///
- /// Reports a diagnostic on any integer literal token with a value less than five.
- ///
- [DiagnosticAnalyzer(LanguageNames.CSharp)]
- private class LiteralUnderFiveAnalyzer : DiagnosticAnalyzer
+ [Fact]
+ [WorkItem(874, "https://github.com/dotnet/roslyn-sdk/issues/874")]
+ public async Task TestTwoIterationsRequiredButOneApplied()
{
- internal static readonly DiagnosticDescriptor Descriptor =
- new DiagnosticDescriptor("LiteralUnderFive", "title", "message", "category", DiagnosticSeverity.Warning, isEnabledByDefault: true);
-
- public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Descriptor);
-
- public override void Initialize(AnalysisContext context)
- {
- context.EnableConcurrentExecution();
- context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
-
- context.RegisterSyntaxNodeAction(HandleNumericLiteralExpression, SyntaxKind.NumericLiteralExpression);
- }
+ var testCode = @"
+class TestClass {
+ int field = [|3|];
+}
+";
+ var fixedCode = @"
+class TestClass {
+ int field = [|4|];
+}
+";
- private void HandleNumericLiteralExpression(SyntaxNodeAnalysisContext context)
+ await new CSharpTest
{
- var node = (LiteralExpressionSyntax)context.Node;
- if (int.TryParse(node.Token.ValueText, out var value) && value < 5)
+ TestCode = testCode,
+ FixedState =
{
- context.ReportDiagnostic(Diagnostic.Create(Descriptor, node.Token.GetLocation()));
- }
- }
+ Sources = { fixedCode },
+ MarkupHandling = MarkupMode.Allow,
+ },
+ CodeActionEquivalenceKey = "IncrementFix:4",
+ CodeActionIndex = 0,
+ }.RunAsync();
}
- [ExportCodeFixProvider(LanguageNames.CSharp)]
- [PartNotDiscoverable]
- private class IncrementFix : CodeFixProvider
+ [Fact]
+ [WorkItem(874, "https://github.com/dotnet/roslyn-sdk/issues/874")]
+ public async Task TestTwoIterationsRequiredButNoneApplied()
{
- public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(LiteralUnderFiveAnalyzer.Descriptor.Id);
-
- public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
+ var testCode = @"
+class TestClass {
+ int field = [|3|];
+}
+";
+ var fixedCode = @"
+class TestClass {
+ int field = [|4|];
+}
+";
- public override Task RegisterCodeFixesAsync(CodeFixContext context)
+ var exception = await Assert.ThrowsAsync(async () =>
{
- foreach (var diagnostic in context.Diagnostics)
+ await new CSharpTest
{
- context.RegisterCodeFix(
- CodeAction.Create(
- "LiteralUnderFive",
- cancellationToken => CreateChangedDocument(context.Document, diagnostic.Location.SourceSpan, cancellationToken),
- nameof(IncrementFix)),
- diagnostic);
- }
-
- return Task.CompletedTask;
- }
+ TestCode = testCode,
+ FixedState =
+ {
+ Sources = { fixedCode },
+ MarkupHandling = MarkupMode.Allow,
+ },
+ CodeActionEquivalenceKey = "IncrementFix:3",
+ CodeActionIndex = 0,
+ }.RunAsync();
+ });
- private async Task CreateChangedDocument(Document document, TextSpan sourceSpan, CancellationToken cancellationToken)
- {
- var tree = (await document.GetSyntaxTreeAsync(cancellationToken))!;
- var root = await tree.GetRootAsync(cancellationToken);
- var token = root.FindToken(sourceSpan.Start);
- var replacement = int.Parse(token.ValueText) + 1;
- var newToken = SyntaxFactory.Literal(token.LeadingTrivia, " " + replacement.ToString(), replacement, token.TrailingTrivia);
- return document.WithSyntaxRoot(root.ReplaceToken(token, newToken));
- }
+ new DefaultVerifier().EqualOrDiff($"Context: Iterative code fix application{Environment.NewLine}The code action equivalence key and index must be consistent when both are specified.", exception.Message);
}
private class CSharpTest : CSharpCodeFixTest
diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing.UnitTests/FixMultipleProjectsTests.cs b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing.UnitTests/FixMultipleProjectsTests.cs
new file mode 100644
index 000000000..35059a454
--- /dev/null
+++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing.UnitTests/FixMultipleProjectsTests.cs
@@ -0,0 +1,306 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Threading.Tasks;
+using Xunit;
+using CSharpTest = Microsoft.CodeAnalysis.Testing.TestFixes.CSharpCodeFixTest<
+ Microsoft.CodeAnalysis.Testing.TestAnalyzers.LiteralUnderFiveAnalyzer,
+ Microsoft.CodeAnalysis.Testing.TestFixes.IncrementFix>;
+using VisualBasicTest = Microsoft.CodeAnalysis.Testing.TestFixes.VisualBasicCodeFixTest<
+ Microsoft.CodeAnalysis.Testing.TestAnalyzers.LiteralUnderFiveAnalyzer,
+ Microsoft.CodeAnalysis.Testing.TestFixes.IncrementFix>;
+
+namespace Microsoft.CodeAnalysis.Testing
+{
+ public class FixMultipleProjectsTests
+ {
+ [Fact]
+ public async Task TwoCSharpProjects_Independent()
+ {
+ await new CSharpTest
+ {
+ TestState =
+ {
+ Sources =
+ {
+ @"public class Type1 { int field = [|4|]; }",
+ @"public class Type2 { int field = [|4|]; }",
+ },
+ AdditionalProjects =
+ {
+ ["Secondary"] =
+ {
+ Sources =
+ {
+ @"public class Type3 { int field = [|4|]; }",
+ @"public class Type4 { int field = [|4|]; }",
+ },
+ },
+ },
+ },
+ FixedState =
+ {
+ Sources =
+ {
+ @"public class Type1 { int field = 5; }",
+ @"public class Type2 { int field = 5; }",
+ },
+ AdditionalProjects =
+ {
+ ["Secondary"] =
+ {
+ Sources =
+ {
+ @"public class Type3 { int field = 5; }",
+ @"public class Type4 { int field = 5; }",
+ },
+ },
+ },
+ },
+ }.RunAsync();
+ }
+
+ [Fact]
+ public async Task TwoVisualBasicProjects_Independent()
+ {
+ await new VisualBasicTest
+ {
+ TestState =
+ {
+ Sources =
+ {
+ @"Public Class Type1 : Private field = [|4|] : End Class",
+ @"Public Class Type2 : Private field = [|4|] : End Class",
+ },
+ AdditionalProjects =
+ {
+ ["Secondary"] =
+ {
+ Sources =
+ {
+ @"Public Class Type3 : Private field = [|4|] : End Class",
+ @"Public Class Type4 : Private field = [|4|] : End Class",
+ },
+ },
+ },
+ },
+ FixedState =
+ {
+ Sources =
+ {
+ @"Public Class Type1 : Private field = 5 : End Class",
+ @"Public Class Type2 : Private field = 5 : End Class",
+ },
+ AdditionalProjects =
+ {
+ ["Secondary"] =
+ {
+ Sources =
+ {
+ @"Public Class Type3 : Private field = 5 : End Class",
+ @"Public Class Type4 : Private field = 5 : End Class",
+ },
+ },
+ },
+ },
+ }.RunAsync();
+ }
+
+ [Fact]
+ public async Task OneCSharpProjectOneVisualBasicProject_Independent()
+ {
+ await new CSharpTest
+ {
+ TestState =
+ {
+ Sources =
+ {
+ @"public class Type1 { int field = [|4|]; }",
+ @"public class Type2 { int field = [|4|]; }",
+ },
+ AdditionalProjects =
+ {
+ ["Secondary", LanguageNames.VisualBasic] =
+ {
+ Sources =
+ {
+ @"Public Class Type3 : Private field = [|4|] : End Class",
+ @"Public Class Type4 : Private field = [|4|] : End Class",
+ },
+ },
+ },
+ },
+ FixedState =
+ {
+ Sources =
+ {
+ @"public class Type1 { int field = 5; }",
+ @"public class Type2 { int field = 5; }",
+ },
+ AdditionalProjects =
+ {
+ ["Secondary", LanguageNames.VisualBasic] =
+ {
+ Sources =
+ {
+ @"Public Class Type3 : Private field = 5 : End Class",
+ @"Public Class Type4 : Private field = 5 : End Class",
+ },
+ },
+ },
+ },
+ }.RunAsync();
+ }
+
+ [Fact]
+ public async Task OneVisualBasicProjectOneCSharpProject_Independent()
+ {
+ await new VisualBasicTest
+ {
+ TestState =
+ {
+ Sources =
+ {
+ @"Public Class Type1 : Private field = [|4|] : End Class",
+ @"Public Class Type2 : Private field = [|4|] : End Class",
+ },
+ AdditionalProjects =
+ {
+ ["Secondary", LanguageNames.CSharp] =
+ {
+ Sources =
+ {
+ @"public class Type3 { int field = [|4|]; }",
+ @"public class Type4 { int field = [|4|]; }",
+ },
+ },
+ },
+ },
+ FixedState =
+ {
+ Sources =
+ {
+ @"Public Class Type1 : Private field = 5 : End Class",
+ @"Public Class Type2 : Private field = 5 : End Class",
+ },
+ AdditionalProjects =
+ {
+ ["Secondary", LanguageNames.CSharp] =
+ {
+ Sources =
+ {
+ @"public class Type3 { int field = 5; }",
+ @"public class Type4 { int field = 5; }",
+ },
+ },
+ },
+ },
+ }.RunAsync();
+ }
+
+ [Fact]
+ public async Task TwoCSharpProjects_Independent_UnexpectedDiagnostic()
+ {
+ var exception = await Assert.ThrowsAsync(async () =>
+ {
+ await new CSharpTest
+ {
+ TestState =
+ {
+ Sources =
+ {
+ @"public class Type1 { int field = [|4|]; }",
+ @"public class Type2 { int field = [|4|]; }",
+ },
+ AdditionalProjects =
+ {
+ ["Secondary"] =
+ {
+ Sources =
+ {
+ @"public class Type3 { int field = [|4|]; }",
+ @"public class Type4 { int field = [|4|]; }",
+ },
+ },
+ },
+ },
+ FixedState =
+ {
+ Sources =
+ {
+ @"public class Type1 { int field = 5; }",
+ @"public class Type2 { int field = 5; }",
+ },
+ AdditionalProjects =
+ {
+ ["Secondary"] =
+ {
+ Sources =
+ {
+ @"public class Type3 { int field = [|5|]; }",
+ @"public class Type4 { int field = 5; }",
+ },
+ },
+ },
+ MarkupHandling = MarkupMode.Allow,
+ },
+ }.RunAsync();
+ });
+
+ new DefaultVerifier().EqualOrDiff($"Context: Diagnostics of fixed state{Environment.NewLine}Mismatch between number of diagnostics returned, expected \"1\" actual \"0\"{Environment.NewLine}{Environment.NewLine}Diagnostics:{Environment.NewLine} NONE.{Environment.NewLine}", exception.Message);
+ }
+
+ [Fact]
+ public async Task TwoCSharpProjects_Independent_UnexpectedContent()
+ {
+ var exception = await Assert.ThrowsAsync(async () =>
+ {
+ await new CSharpTest
+ {
+ TestState =
+ {
+ Sources =
+ {
+ @"public class Type1 { int field = [|4|]; }",
+ @"public class Type2 { int field = [|4|]; }",
+ },
+ AdditionalProjects =
+ {
+ ["Secondary"] =
+ {
+ Sources =
+ {
+ @"public class Type3 { int field = [|4|]; }",
+ @"public class Type4 { int field = [|4|]; }",
+ },
+ },
+ },
+ },
+ FixedState =
+ {
+ Sources =
+ {
+ @"public class Type1 { int field = 5; }",
+ @"public class Type2 { int field = 5; }",
+ },
+ AdditionalProjects =
+ {
+ ["Secondary"] =
+ {
+ Sources =
+ {
+ @"public class Type3 { int field = 5; }",
+ @"public class Type4 { int field = 5; }",
+ },
+ },
+ },
+ },
+ }.RunAsync();
+ });
+
+ new DefaultVerifier().EqualOrDiff($"Context: Iterative code fix application{Environment.NewLine}content of '/Secondary/Test0.cs' did not match. Diff shown with expected as baseline:{Environment.NewLine}-public class Type3 {{ int field = 5; }}{Environment.NewLine}+public class Type3 {{ int field = 5; }}{Environment.NewLine}", exception.Message);
+ }
+ }
+}
diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing.UnitTests/RefactoringValidationTests.cs b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing.UnitTests/RefactoringValidationTests.cs
index b47c232dc..03780afb8 100644
--- a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing.UnitTests/RefactoringValidationTests.cs
+++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeRefactoring.Testing.UnitTests/RefactoringValidationTests.cs
@@ -290,6 +290,68 @@ public async Task TestNoValidationPassesFull()
}.RunAsync();
}
+ [Fact]
+ [WorkItem(806, "https://github.com/dotnet/roslyn-sdk/issues/806")]
+ public async Task TestWithAdditionalProject_SameLanguage()
+ {
+ await new ReplaceThisWithBaseTest
+ {
+ TestState =
+ {
+ Sources = { "public class Ignored { }" },
+ AdditionalProjects =
+ {
+ ["Additional"] =
+ {
+ Sources = { ReplaceThisWithBaseTestCode },
+ },
+ },
+ },
+ FixedState =
+ {
+ Sources = { "public class Ignored { }" },
+ AdditionalProjects =
+ {
+ ["Additional"] =
+ {
+ Sources = { ReplaceThisWithBaseFixedCode },
+ },
+ },
+ },
+ }.RunAsync();
+ }
+
+ [Fact]
+ [WorkItem(806, "https://github.com/dotnet/roslyn-sdk/issues/806")]
+ public async Task TestWithAdditionalProject_DifferentLanguage()
+ {
+ await new ReplaceThisWithBaseTestVisualBasic
+ {
+ TestState =
+ {
+ Sources = { "Public Class Ignored : End Class" },
+ AdditionalProjects =
+ {
+ ["Additional", LanguageNames.CSharp] =
+ {
+ Sources = { ReplaceThisWithBaseTestCode },
+ },
+ },
+ },
+ FixedState =
+ {
+ Sources = { "Public Class Ignored : End Class" },
+ AdditionalProjects =
+ {
+ ["Additional", LanguageNames.CSharp] =
+ {
+ Sources = { ReplaceThisWithBaseFixedCode },
+ },
+ },
+ },
+ }.RunAsync();
+ }
+
[ExportCodeRefactoringProvider(LanguageNames.CSharp)]
[PartNotDiscoverable]
private class ReplaceThisWithBaseTokenFix : CodeRefactoringProvider
@@ -405,5 +467,30 @@ protected override IEnumerable GetCodeRefactoringProvid
yield return new TCodeRefactoring();
}
}
+
+ private class ReplaceThisWithBaseTestVisualBasic : CodeRefactoringTest
+ where TCodeRefactoring : CodeRefactoringProvider, new()
+ {
+ public override string Language => LanguageNames.VisualBasic;
+
+ public override Type SyntaxKindType => typeof(VisualBasic.SyntaxKind);
+
+ protected override string DefaultFileExt => "vb";
+
+ protected override CompilationOptions CreateCompilationOptions()
+ {
+ return new VisualBasic.VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
+ }
+
+ protected override ParseOptions CreateParseOptions()
+ {
+ return new VisualBasic.VisualBasicParseOptions(VisualBasic.LanguageVersion.Default, DocumentationMode.Diagnose);
+ }
+
+ protected override IEnumerable GetCodeRefactoringProviders()
+ {
+ yield return new TCodeRefactoring();
+ }
+ }
}
}
diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/Microsoft.CodeAnalysis.Testing.Utilities.csproj b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/Microsoft.CodeAnalysis.Testing.Utilities.csproj
index 614d81005..184f5e0fe 100644
--- a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/Microsoft.CodeAnalysis.Testing.Utilities.csproj
+++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/Microsoft.CodeAnalysis.Testing.Utilities.csproj
@@ -36,5 +36,6 @@
+
diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestAnalyzers/LiteralUnderFiveAnalyzer.cs b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestAnalyzers/LiteralUnderFiveAnalyzer.cs
new file mode 100644
index 000000000..e852b0a6a
--- /dev/null
+++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestAnalyzers/LiteralUnderFiveAnalyzer.cs
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Operations;
+
+namespace Microsoft.CodeAnalysis.Testing.TestAnalyzers
+{
+ ///
+ /// Reports a diagnostic on any integer literal with a value less than five.
+ ///
+ [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
+ public class LiteralUnderFiveAnalyzer : DiagnosticAnalyzer
+ {
+ internal const string CurrentValueProperty = nameof(CurrentValueProperty);
+
+ internal static readonly DiagnosticDescriptor Descriptor =
+ new DiagnosticDescriptor("LiteralUnderFive", "title", "message", "category", DiagnosticSeverity.Warning, isEnabledByDefault: true);
+
+ public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Descriptor);
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.EnableConcurrentExecution();
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+
+ context.RegisterOperationAction(HandleLiteralOperation, OperationKind.Literal);
+ }
+
+ private void HandleLiteralOperation(OperationAnalysisContext context)
+ {
+ var operation = (ILiteralOperation)context.Operation;
+ if (operation.ConstantValue.HasValue
+ && operation.ConstantValue.Value is int value
+ && value < 5)
+ {
+ var properties = ImmutableDictionary.Empty
+ .Add(CurrentValueProperty, value.ToString());
+ context.ReportDiagnostic(Diagnostic.Create(Descriptor, operation.Syntax.GetLocation(), properties));
+ }
+ }
+ }
+}
diff --git a/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestFixes/IncrementFix.cs b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestFixes/IncrementFix.cs
new file mode 100644
index 000000000..f7d0765e8
--- /dev/null
+++ b/tests/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Utilities/TestFixes/IncrementFix.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.Collections.Immutable;
+using System.Composition;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Editing;
+using Microsoft.CodeAnalysis.Testing.TestAnalyzers;
+using Microsoft.CodeAnalysis.Text;
+using Xunit;
+
+namespace Microsoft.CodeAnalysis.Testing.TestFixes
+{
+ [ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic)]
+ [PartNotDiscoverable]
+ public class IncrementFix : CodeFixProvider
+ {
+ public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(LiteralUnderFiveAnalyzer.Descriptor.Id);
+
+ public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
+
+ public override Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ foreach (var diagnostic in context.Diagnostics)
+ {
+ context.RegisterCodeFix(
+ CodeAction.Create(
+ "LiteralUnderFive",
+ cancellationToken => CreateChangedDocument(context.Document, diagnostic.Location.SourceSpan, cancellationToken),
+ $"{nameof(IncrementFix)}:{int.Parse(diagnostic.Properties[LiteralUnderFiveAnalyzer.CurrentValueProperty]!) + 1}"),
+ diagnostic);
+ }
+
+ return Task.CompletedTask;
+ }
+
+ private async Task CreateChangedDocument(Document document, TextSpan sourceSpan, CancellationToken cancellationToken)
+ {
+ var tree = (await document.GetSyntaxTreeAsync(cancellationToken))!;
+ var root = await tree.GetRootAsync(cancellationToken);
+ var token = root.FindToken(sourceSpan.Start);
+ var replacement = int.Parse(token.ValueText) + 1;
+ var generator = SyntaxGenerator.GetGenerator(document);
+
+ var originalLeadingTrivia = token.LeadingTrivia;
+ SyntaxTriviaList newLeadingTrivia;
+ Assert.Equal(0, originalLeadingTrivia.Count);
+ if (document.Project.Language == LanguageNames.CSharp)
+ {
+ newLeadingTrivia = CSharp.SyntaxFactory.TriviaList(CSharp.SyntaxFactory.Space);
+ }
+ else
+ {
+ newLeadingTrivia = VisualBasic.SyntaxFactory.TriviaList(VisualBasic.SyntaxFactory.Space);
+ }
+
+ var newExpression = generator.LiteralExpression(replacement).WithLeadingTrivia(newLeadingTrivia).WithTrailingTrivia(token.TrailingTrivia);
+ return document.WithSyntaxRoot(root.ReplaceNode(token.Parent!, newExpression));
+ }
+ }
+}