diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c61d15ed446b4..0c2c21335a806 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -8,6 +8,7 @@ docs/compilers @dotnet/roslyn-compiler docs/ide @dotnet/roslyn-ide eng/ @dotnet/roslyn-infrastructure +eng/SourceBuild* @dotnet/source-build-internal scripts/ @dotnet/roslyn-infrastructure src/Analyzers/ @dotnet/roslyn-ide diff --git a/.gitignore b/.gitignore index 1b5de22f73c67..960bf567817ac 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ .dotnet/ .tools/ .packages/ +.nuget/ # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets !packages/*/build/ diff --git a/Roslyn.sln b/Roslyn.sln index e68230672e34d..290580925c9e5 100644 --- a/Roslyn.sln +++ b/Roslyn.sln @@ -523,10 +523,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Exte EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.UnitTests", "src\Tools\ExternalAccess\RazorCompilerTest\Microsoft.CodeAnalysis.ExternalAccess.RazorCompiler.UnitTests.csproj", "{828FD0DB-9927-42AC-B6C2-D1514965D6C3}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.LanguageServer", "src\Features\LanguageServer\Microsoft.CodeAnalysis.LanguageServer\Microsoft.CodeAnalysis.LanguageServer.csproj", "{2A3C94F7-5B5E-4CDC-B645-672815E61DEB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.LanguageServer.UnitTests", "src\Features\LanguageServer\Microsoft.CodeAnalysis.LanguageServer.UnitTests\Microsoft.CodeAnalysis.LanguageServer.UnitTests.csproj", "{9A90AA02-4275-40ED-B1F1-731AF17E675C}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Net.Compilers.Toolset.Framework.Package", "src\NuGet\Microsoft.Net.Compilers.Toolset\Framework\Microsoft.Net.Compilers.Toolset.Framework.Package.csproj", "{521ADC3E-CC15-414B-9356-D87C5BCF3A24}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LanguageServer", "LanguageServer", "{D449D505-CC6A-4E0B-AF1B-976E2D0AE67A}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.LanguageServices.DevKit", "src\VisualStudio\DevKit\Impl\Microsoft.VisualStudio.LanguageServices.DevKit.csproj", "{9B7AC5C2-293D-438D-B9A2-1EDDC2C6BF00}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.CSharp.Features.UnitTests", "src\Features\CSharpTest\Microsoft.CodeAnalysis.CSharp.Features.UnitTests.csproj", "{E645B517-5766-46FB-AA4A-D4D30C9E3BE6}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Features.UnitTests", "src\Features\Test\Microsoft.CodeAnalysis.Features.UnitTests.csproj", "{9296F799-5DE4-4E12-A68E-AAC39B0EB90A}" @@ -1295,10 +1301,22 @@ Global {828FD0DB-9927-42AC-B6C2-D1514965D6C3}.Debug|Any CPU.Build.0 = Debug|Any CPU {828FD0DB-9927-42AC-B6C2-D1514965D6C3}.Release|Any CPU.ActiveCfg = Release|Any CPU {828FD0DB-9927-42AC-B6C2-D1514965D6C3}.Release|Any CPU.Build.0 = Release|Any CPU + {2A3C94F7-5B5E-4CDC-B645-672815E61DEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A3C94F7-5B5E-4CDC-B645-672815E61DEB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A3C94F7-5B5E-4CDC-B645-672815E61DEB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A3C94F7-5B5E-4CDC-B645-672815E61DEB}.Release|Any CPU.Build.0 = Release|Any CPU + {9A90AA02-4275-40ED-B1F1-731AF17E675C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9A90AA02-4275-40ED-B1F1-731AF17E675C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9A90AA02-4275-40ED-B1F1-731AF17E675C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9A90AA02-4275-40ED-B1F1-731AF17E675C}.Release|Any CPU.Build.0 = Release|Any CPU {521ADC3E-CC15-414B-9356-D87C5BCF3A24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {521ADC3E-CC15-414B-9356-D87C5BCF3A24}.Debug|Any CPU.Build.0 = Debug|Any CPU {521ADC3E-CC15-414B-9356-D87C5BCF3A24}.Release|Any CPU.ActiveCfg = Release|Any CPU {521ADC3E-CC15-414B-9356-D87C5BCF3A24}.Release|Any CPU.Build.0 = Release|Any CPU + {9B7AC5C2-293D-438D-B9A2-1EDDC2C6BF00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B7AC5C2-293D-438D-B9A2-1EDDC2C6BF00}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B7AC5C2-293D-438D-B9A2-1EDDC2C6BF00}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B7AC5C2-293D-438D-B9A2-1EDDC2C6BF00}.Release|Any CPU.Build.0 = Release|Any CPU {E645B517-5766-46FB-AA4A-D4D30C9E3BE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E645B517-5766-46FB-AA4A-D4D30C9E3BE6}.Debug|Any CPU.Build.0 = Debug|Any CPU {E645B517-5766-46FB-AA4A-D4D30C9E3BE6}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -1565,7 +1583,10 @@ Global {8BC50AFF-1EBF-4E9A-AEBB-04F387AA800F} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC} {E5E0BF73-95F7-4BC3-8443-2336C4FF4297} = {8977A560-45C2-4EC2-A849-97335B382C74} {828FD0DB-9927-42AC-B6C2-D1514965D6C3} = {8977A560-45C2-4EC2-A849-97335B382C74} + {2A3C94F7-5B5E-4CDC-B645-672815E61DEB} = {D449D505-CC6A-4E0B-AF1B-976E2D0AE67A} + {9A90AA02-4275-40ED-B1F1-731AF17E675C} = {D449D505-CC6A-4E0B-AF1B-976E2D0AE67A} {521ADC3E-CC15-414B-9356-D87C5BCF3A24} = {C52D8057-43AF-40E6-A01B-6CDBB7301985} + {9B7AC5C2-293D-438D-B9A2-1EDDC2C6BF00} = {8DBA5174-B0AA-4561-82B1-A46607697753} {E645B517-5766-46FB-AA4A-D4D30C9E3BE6} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} {9296F799-5DE4-4E12-A68E-AAC39B0EB90A} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} {57B7C0AA-E14A-41F6-AD06-FB3937F66FC2} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6} @@ -1624,6 +1645,8 @@ Global src\Compilers\Server\VBCSCompiler\VBCSCompilerCommandLine.projitems*{9508f118-f62e-4c16-a6f4-7c3b56e166ad}*SharedItemsImports = 5 src\Compilers\VisualBasic\vbc\VbcCommandLine.projitems*{975cd834-45f4-4ea0-a395-cb60dbd0e214}*SharedItemsImports = 5 src\Workspaces\SharedUtilitiesAndExtensions\Workspace\Core\WorkspaceExtensions.projitems*{99f594b1-3916-471d-a761-a6731fc50e9a}*SharedItemsImports = 13 + src\Dependencies\Collections\Microsoft.CodeAnalysis.Collections.projitems*{9b7ac5c2-293d-438d-b9a2-1eddc2c6bf00}*SharedItemsImports = 5 + src\Dependencies\PooledObjects\Microsoft.CodeAnalysis.PooledObjects.projitems*{9b7ac5c2-293d-438d-b9a2-1eddc2c6bf00}*SharedItemsImports = 5 src\Analyzers\VisualBasic\CodeFixes\VisualBasicCodeFixes.projitems*{9f9ccc78-7487-4127-9d46-db23e501f001}*SharedItemsImports = 13 src\Analyzers\CSharp\CodeFixes\CSharpCodeFixes.projitems*{a07abcf5-bc43-4ee9-8fd8-b2d77fd54d73}*SharedItemsImports = 5 src\Workspaces\SharedUtilitiesAndExtensions\Workspace\CSharp\CSharpWorkspaceExtensions.projitems*{a07abcf5-bc43-4ee9-8fd8-b2d77fd54d73}*SharedItemsImports = 5 diff --git a/azure-pipelines-official.yml b/azure-pipelines-official.yml index d4c303b6fefaa..ddd44ed2beb85 100644 --- a/azure-pipelines-official.yml +++ b/azure-pipelines-official.yml @@ -5,6 +5,7 @@ trigger: - main-vs-deps - release/dev16.*-vs-deps - release/dev17.* + - features/lsp_tools_host exclude: - release/dev17.0 pr: none @@ -81,7 +82,7 @@ stages: displayName: Build and Test pool: name: NetCore1ESPool-Svc-Internal - demands: ImageOverride -equals windows.vs2022.amd64 + demands: ImageOverride -equals windows.vs2022preview.amd64 jobs: - ${{ if eq(variables['Build.SourceBranch'], 'refs/heads/release/dev17.7') }}: @@ -130,6 +131,12 @@ stages: - powershell: Write-Host "##vso[task.setvariable variable=VisualStudio.DropName]Products/$(System.TeamProject)/$(Build.Repository.Name)/$(SourceBranchName)/$(Build.BuildNumber)" displayName: Setting VisualStudio.DropName variable + - task: NodeTool@0 + inputs: + versionSpec: '16.x' + displayName: 'Install Node.js' + + - task: NuGetToolInstaller@0 inputs: versionSpec: '4.9.2' @@ -303,6 +310,21 @@ stages: ArtifactName: 'PackageArtifacts' condition: succeeded() + # Publish language server package + - powershell: Write-Host "##vso[task.setvariable variable=NPMFileName]$((ls -file $(Build.SourcesDirectory)\artifacts\packages\Release\NPM\ | select -First 1).FullName)" + displayName: Setting NPM Package Variable + + # Authenticates the .npmrc file for publishing to the internal AzDO feed. + # See: https://learn.microsoft.com/azure/devops/pipelines/tasks/package/npm-authenticate?view=azure-devops + - task: npmAuthenticate@0 + displayName: Authenticate NPM Feed + inputs: + workingFile: $(Build.SourcesDirectory)/src/VisualStudio/DevKit/Impl/.npmrc + customEndpoint: devdiv-vs-green-npm-package-feed + + - script: npm publish --userconfig $(Build.SourcesDirectory)\src\VisualStudio\DevKit\Impl\.npmrc $(NPMFileName) + displayName: Publish Language Server NPM Package + # Publish Asset Manifests for Build Asset Registry job - task: PublishBuildArtifacts@1 displayName: Publish Asset Manifests diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e4f0fff4f588b..8282e102b2294 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -29,6 +29,61 @@ pr: - CONTRIBUTING.md - README.md +variables: + # This value is conditionally overriden by the variable group DotNet-HelixApi-Access. + # ADO only lets us conditionally include a variable group on individual stages. + - name: HelixApiAccessToken + value: '' + + # Set pool / queue name variables depending on which instance we're running in. + - name: PoolName + ${{ if eq(variables['System.TeamProject'], 'public') }}: + value: NetCore-Public + ${{ else }}: + value: NetCore1ESPool-Internal + + - name: Vs2022PreviewQueueName + ${{ if eq(variables['System.TeamProject'], 'public') }}: + value: windows.vs2022preview.amd64.open + ${{ else }}: + value: windows.vs2022preview.amd64 + + - name: Vs2022QueueName + ${{ if eq(variables['System.TeamProject'], 'public') }}: + value: windows.vs2022.amd64.open + ${{ else }}: + value: windows.vs2022.amd64 + + - name: UbuntuQueueName + ${{ if eq(variables['System.TeamProject'], 'public') }}: + value: Build.Ubuntu.1804.Amd64.Open + ${{ else }}: + value: Build.Ubuntu.1804.Amd64 + + - name: HelixWindowsQueueName + ${{ if eq(variables['System.TeamProject'], 'public') }}: + value: Windows.10.Amd64.Open + ${{ else }}: + value: Windows.10.Amd64 + + - name: HelixWindowsSpanishQueueName + ${{ if eq(variables['System.TeamProject'], 'public') }}: + value: Windows.10.Amd64.Server2022.ES.Open + ${{ else }}: + value: Windows.10.Amd64.Server2022.ES + + - name: HelixUbuntuQueueName + ${{ if eq(variables['System.TeamProject'], 'public') }}: + value: Ubuntu.1804.Amd64.Open + ${{ else }}: + value: Ubuntu.1804.Amd64 + + - name: HelixMacOsQueueName + ${{ if eq(variables['System.TeamProject'], 'public') }}: + value: OSX.1015.Amd64.Open + ${{ else }}: + value: OSX.1015.Amd64 + stages: - stage: Windows_Debug_Build dependsOn: [] @@ -38,7 +93,8 @@ stages: jobName: Build_Windows_Debug testArtifactName: Transport_Artifacts_Windows_Debug configuration: Debug - queueName: windows.vs2022preview.amd64.open + poolName: $(PoolName) + queueName: $(Vs2022PreviewQueueName) restoreArguments: -msbuildEngine dotnet /p:UsingToolVSSDK=false /p:GenerateSatelliteAssemblies=false buildArguments: -msbuildEngine dotnet /p:UsingToolVSSDK=false /p:GenerateSatelliteAssemblies=false /p:PublishReadyToRun=false @@ -50,7 +106,8 @@ stages: jobName: Build_Windows_Release testArtifactName: Transport_Artifacts_Windows_Release configuration: Release - queueName: windows.vs2022preview.amd64.open + poolName: $(PoolName) + queueName: $(Vs2022PreviewQueueName) restoreArguments: -msbuildEngine dotnet /p:UsingToolVSSDK=false /p:GenerateSatelliteAssemblies=false buildArguments: -msbuildEngine dotnet /p:UsingToolVSSDK=false /p:GenerateSatelliteAssemblies=false /p:PublishReadyToRun=false @@ -62,7 +119,8 @@ stages: jobName: Build_Unix_Debug testArtifactName: Transport_Artifacts_Unix_Debug configuration: Debug - queueName: Build.Ubuntu.1804.Amd64.Open + poolName: $(PoolName) + queueName: $(UbuntuQueueName) - stage: Source_Build dependsOn: [] @@ -90,6 +148,9 @@ stages: - stage: Windows_Debug_Desktop dependsOn: Windows_Debug_Build + variables: + - ${{ if ne(variables['System.TeamProject'], 'public') }}: + - group: DotNet-HelixApi-Access jobs: - ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: - template: eng/pipelines/test-windows-job.yml @@ -99,6 +160,8 @@ stages: testArtifactName: Transport_Artifacts_Windows_Debug configuration: Debug testArguments: -testDesktop -testArch x86 + helixQueueName: $(HelixWindowsQueueName) + helixApiAccessToken: $(HelixApiAccessToken) - template: eng/pipelines/test-windows-job.yml parameters: @@ -107,9 +170,14 @@ stages: testArtifactName: Transport_Artifacts_Windows_Debug configuration: Debug testArguments: -testDesktop -testArch x64 + helixQueueName: $(HelixWindowsQueueName) + helixApiAccessToken: $(HelixApiAccessToken) - stage: Windows_Release_Desktop dependsOn: Windows_Release_Build + variables: + - ${{ if ne(variables['System.TeamProject'], 'public') }}: + - group: DotNet-HelixApi-Access jobs: - template: eng/pipelines/test-windows-job.yml parameters: @@ -118,6 +186,8 @@ stages: testArtifactName: Transport_Artifacts_Windows_Release configuration: Release testArguments: -testDesktop -testArch x86 + helixQueueName: $(HelixWindowsQueueName) + helixApiAccessToken: $(HelixApiAccessToken) - ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: - template: eng/pipelines/test-windows-job.yml @@ -127,6 +197,8 @@ stages: testArtifactName: Transport_Artifacts_Windows_Release configuration: Release testArguments: -testDesktop -testArch x64 + helixQueueName: $(HelixWindowsQueueName) + helixApiAccessToken: $(HelixApiAccessToken) - template: eng/pipelines/test-windows-job.yml parameters: @@ -134,10 +206,15 @@ stages: jobName: Test_Windows_Desktop_Spanish_Release_64 testArtifactName: Transport_Artifacts_Windows_Release configuration: Release - testArguments: -testDesktop -testArch x64 -helixQueueName Windows.10.Amd64.Server2022.ES.Open + testArguments: -testDesktop -testArch x64 + helixQueueName: $(HelixWindowsSpanishQueueName) + helixApiAccessToken: $(HelixApiAccessToken) - stage: Windows_Debug_CoreClr dependsOn: Windows_Debug_Build + variables: + - ${{ if ne(variables['System.TeamProject'], 'public') }}: + - group: DotNet-HelixApi-Access jobs: - template: eng/pipelines/test-windows-job.yml parameters: @@ -146,6 +223,8 @@ stages: testArtifactName: Transport_Artifacts_Windows_Debug configuration: Debug testArguments: -testCoreClr + helixQueueName: $(HelixWindowsQueueName) + helixApiAccessToken: $(HelixApiAccessToken) - ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: - template: eng/pipelines/test-windows-job-single-machine.yml @@ -154,6 +233,8 @@ stages: jobName: Test_Windows_CoreClr_Debug_Single_Machine testArtifactName: Transport_Artifacts_Windows_Debug configuration: Debug + poolName: $(PoolName) + queueName: $(Vs2022QueueName) testArguments: -testCoreClr - template: eng/pipelines/test-windows-job.yml @@ -163,6 +244,8 @@ stages: testArtifactName: Transport_Artifacts_Windows_Debug configuration: Debug testArguments: -testCoreClr -testIOperation -testCompilerOnly + helixQueueName: $(HelixWindowsQueueName) + helixApiAccessToken: $(HelixApiAccessToken) # This leg runs almost all the compiler tests supported on CoreCLR, but # with additional validation for used assemblies and GetEmitDiagnostics @@ -173,9 +256,14 @@ stages: testArtifactName: Transport_Artifacts_Windows_Debug configuration: Debug testArguments: -testCoreClr -testUsedAssemblies -testCompilerOnly + helixQueueName: $(HelixWindowsQueueName) + helixApiAccessToken: $(HelixApiAccessToken) - stage: Windows_Release_CoreClr dependsOn: Windows_Release_Build + variables: + - ${{ if ne(variables['System.TeamProject'], 'public') }}: + - group: DotNet-HelixApi-Access jobs: - template: eng/pipelines/test-windows-job.yml parameters: @@ -184,9 +272,14 @@ stages: testArtifactName: Transport_Artifacts_Windows_Release configuration: Release testArguments: -testCoreClr + helixQueueName: $(HelixWindowsQueueName) + helixApiAccessToken: $(HelixApiAccessToken) - stage: Unix_Debug_CoreClr dependsOn: Unix_Build + variables: + - ${{ if ne(variables['System.TeamProject'], 'public') }}: + - group: DotNet-HelixApi-Access jobs: - template: eng/pipelines/test-unix-job.yml parameters: @@ -194,7 +287,9 @@ stages: jobName: Test_Linux_Debug testArtifactName: Transport_Artifacts_Unix_Debug configuration: Debug - testArguments: --testCoreClr --helixQueueName Ubuntu.1804.Amd64.Open + testArguments: --testCoreClr + helixQueueName: $(HelixUbuntuQueueName) + helixApiAccessToken: $(HelixApiAccessToken) - ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: - template: eng/pipelines/test-unix-job-single-machine.yml @@ -204,7 +299,8 @@ stages: testArtifactName: Transport_Artifacts_Unix_Debug configuration: Debug testArguments: --testCoreClr - queueName: Build.Ubuntu.1804.Amd64.Open + poolName: $(PoolName) + queueName: $(UbuntuQueueName) - ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: - template: eng/pipelines/test-unix-job.yml @@ -213,7 +309,9 @@ stages: jobName: Test_macOS_Debug testArtifactName: Transport_Artifacts_Unix_Debug configuration: Debug - testArguments: --testCoreClr --helixQueueName OSX.1015.Amd64.Open + testArguments: --testCoreClr + helixQueueName: $(HelixMacOsQueueName) + helixApiAccessToken: $(HelixApiAccessToken) - stage: Correctness dependsOn: [] @@ -221,6 +319,7 @@ stages: - template: eng/pipelines/evaluate-changed-files.yml parameters: jobName: Determine_Changes + poolName: $(PoolName) vmImageName: ubuntu-latest paths: - subset: compilers @@ -234,8 +333,8 @@ stages: - job: Correctness_Build_Artifacts dependsOn: Determine_Changes pool: - name: NetCore-Public - demands: ImageOverride -equals windows.vs2022preview.amd64.open + name: $(PoolName) + demands: ImageOverride -equals $(Vs2022PreviewQueueName) timeoutInMinutes: 90 variables: - template: eng/pipelines/variables-build.yml @@ -284,8 +383,8 @@ stages: dependsOn: Determine_Changes condition: or(ne(variables['Build.Reason'], 'PullRequest'), eq(dependencies.Determine_Changes.outputs['SetPathVars_compilers.containsChange'], 'true')) pool: - name: NetCore-Public - demands: ImageOverride -equals windows.vs2022preview.amd64.open + name: $(PoolName) + demands: ImageOverride -equals $(Vs2022PreviewQueueName) timeoutInMinutes: 90 variables: - template: eng/pipelines/variables-build.yml @@ -306,8 +405,8 @@ stages: dependsOn: Determine_Changes condition: or(ne(variables['Build.Reason'], 'PullRequest'), eq(dependencies.Determine_Changes.outputs['SetPathVars_compilers.containsChange'], 'true')) pool: - name: NetCore-Public - demands: ImageOverride -equals windows.vs2022preview.amd64.open + name: $(PoolName) + demands: ImageOverride -equals $(Vs2022PreviewQueueName) timeoutInMinutes: 90 variables: - template: eng/pipelines/variables-build.yml @@ -322,8 +421,8 @@ stages: dependsOn: Determine_Changes condition: ne(variables['Build.Reason'], 'Pull Request') pool: - name: NetCore-Public - demands: ImageOverride -equals windows.vs2022preview.amd64.open + name: $(PoolName) + demands: ImageOverride -equals $(Vs2022PreviewQueueName) timeoutInMinutes: 90 variables: - template: eng/pipelines/variables-build.yml @@ -348,8 +447,8 @@ stages: dependsOn: Determine_Changes condition: or(ne(variables['Build.Reason'], 'PullRequest'), eq(dependencies.Determine_Changes.outputs['SetPathVars_compilers.containsChange'], 'true')) pool: - name: NetCore-Public - demands: ImageOverride -equals windows.vs2022preview.amd64.open + name: $(PoolName) + demands: ImageOverride -equals $(Vs2022PreviewQueueName) timeoutInMinutes: 90 variables: - template: eng/pipelines/variables-build.yml @@ -377,8 +476,8 @@ stages: - job: Correctness_Analyzers pool: - name: NetCore-Public - demands: ImageOverride -equals Build.Ubuntu.1804.Amd64.Open + name: $(PoolName) + demands: ImageOverride -equals $(UbuntuQueueName) timeoutInMinutes: 35 variables: - template: eng/pipelines/variables-build.yml diff --git a/docs/Language Feature Status.md b/docs/Language Feature Status.md index df3a8363fa991..6bc04b2854ab2 100644 --- a/docs/Language Feature Status.md +++ b/docs/Language Feature Status.md @@ -19,7 +19,7 @@ efforts behind them. | [Default in deconstruction](https://github.com/dotnet/roslyn/pull/25562) | [decon-default](https://github.com/dotnet/roslyn/tree/features/decon-default) | [In Progress](https://github.com/dotnet/roslyn/issues/25559) | [jcouv](https://github.com/jcouv) | [gafter](https://github.com/gafter) | | [jcouv](https://github.com/jcouv) | | [Collection Literals](https://github.com/dotnet/csharplang/issues/5354) | [CollectionLiterals](https://github.com/dotnet/roslyn/tree/features/CollectionLiterals) | [In Progress](https://github.com/dotnet/roslyn/issues/66418) | [cston](https://github.com/cston) | [333fred](https://github.com/333fred), [RikkiGibson](https://github.com/RikkiGibson) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | | [Roles/Extensions](https://github.com/dotnet/csharplang/issues/5497) | [roles](https://github.com/dotnet/roslyn/tree/features/roles) | [In Progress](https://github.com/dotnet/roslyn/issues/66722) | [jcouv](https://github.com/jcouv) | [AlekseyTs](https://github.com/AlekseyTs), [jjonescz](https://github.com/jjonescz) | | [MadsTorgersen](https://github.com/MadsTorgersen) | -| [Interceptors](https://github.com/dotnet/csharplang/issues/7009) | [interceptors](https://github.com/dotnet/roslyn/tree/features/interceptors) | [In Progress](https://github.com/dotnet/roslyn/issues/67421) | [RikkiGibson](https://github.com/RikkiGibson) | [cston](https://github.com/cston), [jcouv](https://github.com/jcouv) | [beccamc](https://github.com/beccamc) | [RikkiGibson](https://github.com/RikkiGibson) | +| [Interceptors](https://github.com/dotnet/csharplang/issues/7009) | [interceptors](https://github.com/dotnet/roslyn/tree/features/interceptors) | [In Progress](https://github.com/dotnet/roslyn/issues/67421) | [RikkiGibson](https://github.com/RikkiGibson) | [cston](https://github.com/cston), [jcouv](https://github.com/jcouv) | [akhera99](https://github.com/akhera99) | [RikkiGibson](https://github.com/RikkiGibson) | | [Inline Arrays](https://github.com/dotnet/csharplang/blob/main/proposals/inline-arrays.md) | [InlineArrays](https://github.com/dotnet/roslyn/tree/features/InlineArrays) | [In Progress](https://github.com/dotnet/roslyn/issues/67826) | [AlekseyTs](https://github.com/AlekseyTs) | [cston](https://github.com/cston), [jjonescz](https://github.com/jjonescz) | | | | [ref readonly parameters](https://github.com/dotnet/csharplang/issues/6010) | | [In Progress](https://github.com/dotnet/roslyn/issues/68056) | [jjonescz](https://github.com/jjonescz) | [jcouv](https://github.com/jcouv), [AlekseyTs](https://github.com/AlekseyTs) | [akhera99](https://github.com/akhera99) | [jaredpar](https://github.com/jaredpar) diff --git a/docs/features/interceptors.md b/docs/features/interceptors.md new file mode 100644 index 0000000000000..83ec2dd26a944 --- /dev/null +++ b/docs/features/interceptors.md @@ -0,0 +1,195 @@ +# Interceptors + +## Summary +[summary]: #summary + +*Interceptors* are an experimental compiler feature planned to ship in .NET 8. The feature may be subject to breaking changes or removal in a future release. + +An *interceptor* is a method which can declaratively substitute a call to an *interceptable* method with a call to itself at compile time. This substitution occurs by having the interceptor declare the source locations of the calls that it intercepts. This provides a limited facility to change the semantics of existing code by adding new code to a compilation (e.g. in a source generator). + +```cs +using System; +using System.Runtime.CompilerServices; + +var c = new C(); +c.InterceptableMethod(1); // (L1,C1): prints "interceptor 1" +c.InterceptableMethod(1); // (L2,C2): prints "other interceptor 1" +c.InterceptableMethod(2); // (L3,C3): prints "other interceptor 2" +c.InterceptableMethod(1); // prints "interceptable 1" + +class C +{ + public void InterceptableMethod(int param) + { + Console.WriteLine($"interceptable {param}"); + } +} + +// generated code +static class D +{ + [InterceptsLocation("Program.cs", line: /*L1*/, character: /*C1*/)] // refers to the call at (L1, C1) + public static void InterceptorMethod(this C c, int param) + { + Console.WriteLine($"interceptor {param}"); + } + + [InterceptsLocation("Program.cs", line: /*L2*/, character: /*C2*/)] // refers to the call at (L2, C2) + [InterceptsLocation("Program.cs", line: /*L3*/, character: /*C3*/)] // refers to the call at (L3, C3) + public static void OtherInterceptorMethod(this C c, int param) + { + Console.WriteLine($"other interceptor {param}"); + } +} +``` + +## Detailed design +[design]: #detailed-design + +### InterceptsLocationAttribute + +A method indicates that it is an *interceptor* by adding one or more `[InterceptsLocation]` attributes. These attributes refer to the source locations of the calls it intercepts. + +```cs +namespace System.Runtime.CompilerServices +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + public sealed class InterceptsLocationAttribute(string filePath, int line, int character) : Attribute + { + } +} +``` + +Any "ordinary method" (i.e. with `MethodKind.Ordinary`) can have its calls intercepted. + +`[InterceptsLocation]` attributes included in source are emitted to the resulting assembly, just like other custom attributes. + +PROTOTYPE(ic): We may want to recognize `file class InterceptsLocationAttribute` as a valid declaration of the attribute, to allow generators to bring the attribute in without conflicting with other generators which may also be bringing the attribute in. See open question in [User opt-in](#user-opt-in). +https://github.com/dotnet/roslyn/issues/67079 is a bug which causes file-local source declarations of well-known attributes to be generally treated as known. When that bug is fixed, we may want to single out `InterceptsLocationAttribute` as "recognized, even though they are file-local". + +#### File paths + +File paths used in `[InterceptsLocation]` are expected to have `/pathmap` substitution already applied. Generators should accomplish this by locally recreating the file path transformation performed by the compiler: + +```cs +using Microsoft.CodeAnalysis; + +string GetInterceptorFilePath(SyntaxTree tree, Compilation compilation) +{ + return compilation.Options.SourceReferenceResolver?.NormalizePath(tree.FilePath, baseFilePath: null) ?? tree.FilePath; +} +``` + +The file path given in the attribute must be equal by ordinal comparison to the value given by the above function. + +The compiler does not map `#line` directives when determining if an `[InterceptsLocation]` attribute intercepts a particular call in syntax. + +#### Position + +Line and column numbers in `[InterceptsLocation]` are 1-indexed to match existing places where source locations are displayed to the user. For example, in `Diagnostic.ToString`. + +The location of the call is the location of the simple name syntax which denotes the interceptable method. For example, in `app.MapGet(...)`, the name syntax for `MapGet` would be considered the location of the call. For a static method call like `System.Console.WriteLine(...)`, the name syntax for `WriteLine` is the location of the call. If we allow intercepting calls to property accessors in the future (e.g `obj.Property`), we would also be able to use the name syntax in this way. + +#### Attribute creation + +The goal of the above decisions is to make it so that when source generators are filling in `[InterceptsLocation(...)]`, they simply need to read `nameSyntax.SyntaxTree.FilePath` and `nameSyntax.GetLineSpan().Span.Start` for the exact file path and position information they need to use. + +We should provide samples of recommended coding patterns for generator authors to show correct usage of these, including the "translation" from 0-indexed to 1-indexed positions. + +### Non-invocation method usages + +Conversion to delegate type, address-of, etc. usages of methods cannot be intercepted. + +Interception can only occur for calls to ordinary member methods--not constructors, delegates, properties, local functions, operators, etc. Support for more member kinds may be added in the future. + +### Arity + +Interceptors cannot have type parameters or be declared in generic types at any level of nesting. + +This limitation prevents interceptors from matching the signature of an interceptable call in cases where the interceptable call uses type parameters which are not in scope at the interceptor declaration. We can consider adjusting the rules to alleviate this limitation if compelling scenarios arise for it in the future. + +```cs +using System.Runtime.CompilerServices; + +class C +{ + public static void InterceptableMethod(T1 t) => throw null!; +} + +static class Program +{ + public static void M(T2 t) + { + C.InterceptableMethod(t); + } +} + +static class D +{ + [InterceptsLocation("Program.cs", 12, 11)] + public static void Interceptor1(object s) => throw null!; +} +``` + +### Signature matching + +When a call is intercepted, the interceptor and interceptable methods must meet the signature matching requirements detailed below: +- When an interceptable instance method is compared to a classic extension method, we use the extension method in reduced form for comparison. The extension method parameter with the `this` modifier is compared to the instance method `this` parameter. +- The returns and parameters, including the `this` parameter, must have the same ref kinds and types. +- A warning is reported instead of an error if a type difference is found where the types are not distinct to the runtime. For example, `object` and `dynamic`. +- No warning or error is reported for a *safe* nullability difference, such as when the interceptable method accepts a `string` parameter, and the interceptor accepts a `string?` parameter. +- Method names and parameter names are not required to match. +- Parameter default values are not required to match. When intercepting, default values on the interceptor method are ignored. +- `params` modifiers are not required to match. +- `scoped` modifiers and `[UnscopedRef]` must be equivalent. +- In general, attributes which normally affect the behavior of the call site, such as `[CallerLineNumber]` are ignored on the interceptor of an intercepted call. + - The only exception to this is when the attribute affects "capabilities" of the method in a way that affects safety, such as with `[UnscopedRef]`. Such attributes are required to match across interceptable and interceptor methods. + +Arity does not need to match between intercepted and interceptor methods. In other words, it is permitted to intercept a generic method with a non-generic interceptor. + +### Conflicting interceptors + +If more than one interceptor refers to the same location, it is a compile-time error. + +If an `[InterceptsLocation]` attribute is found in the compilation which does not refer to the location of an explicit method call, it is a compile-time error. + +### Interceptor accessibility + +An interceptor must be accessible at the location where interception is occurring. + +An interceptor contained in a file-local type is permitted to intercept a call in another file, even though the interceptor is not normally *visible* at the call site. + +This allows generator authors to avoid *polluting lookup* with interceptors, helps avoid name conflicts, and prevents use of interceptors in *unintended positions* from the interceptor author's point-of-view. + +We may also want to consider adjusting behavior of `[EditorBrowsable]` to work in the same compilation. + +### Editor experience + +Interceptors are treated like a post-compilation step in this design. Diagnostics are given for misuse of interceptors, but some diagnostics are only given in the command-line build and not in the IDE. There is limited traceability in the editor for which calls in a compilation are actually being intercepted. If this feature is brought forward past the experimental stage, this limitation will need to be re-examined. + +### User opt-in + +Interceptors will require a feature flag during the experimental phase. The flag can be enabled with `/features=InterceptorsPreview` on the command line or `InterceptorsPreview` in msbuild. + +### Implementation strategy + +During the binding phase, `InterceptsLocationAttribute` usages are decoded and the related data for each usage are collected in a `ConcurrentSet` on the compilation: +- intercepted file-path and location +- attribute location +- attributed method symbol + +At this time, diagnostics are reported for the following conditions: +- problems specific to the attributed interceptor method itself, for example, that it is not an ordinary method. +- syntactic problems specific to the referenced location, for example, that it does not refer to an applicable simple name as defined in [Position](#position) subsection. + +During the lowering phase, when a given `BoundCall` is lowered: +- we check if its syntax contains an applicable simple name +- if so, we lookup whether it is being intercepted, based on data about `InterceptsLocationAttribute` collected during the binding phase. +- if it is being intercepted, we perform an additional step after lowering of the receiver and arguments is completed: + - substitute the interceptable method with the interceptor method on the `BoundCall`. + - if the interceptor is a classic extension method, and the interceptable method is an instance method, we adjust the `BoundCall` to use the receiver as the first argument of the call, "pushing" the other arguments forward, similar to the way it would have bound if the original call were to an extension method in reduced form. + +At this time, diagnostics are reported for the following conditions: +- incompatibility between the interceptor and interceptable methods, for example, in their signatures. +- *duplicate* `[InterceptsLocation]`, that is, multiple interceptors which intercept the same call. +- interceptor is not accessible at the call site. \ No newline at end of file diff --git a/docs/wiki/EnC-Supported-Edits.md b/docs/wiki/EnC-Supported-Edits.md index deb3a47a412c3..c05d40b1121ce 100644 --- a/docs/wiki/EnC-Supported-Edits.md +++ b/docs/wiki/EnC-Supported-Edits.md @@ -1,5 +1,8 @@ -# Supported Edits in Edit & Continue (EnC) -Edit & Continue lets you modify/add to your source code in break-mode while debugging without ever having to restart your debugging session. +# Supported Edits in Edit & Continue (EnC) and Hot Reload on .NET 8 +Hot Reload lets you modify/add to your source code while the application is running, either with debugger attached to the process (F5) or not attached (Ctrl+F5). +Edit & Continue lets you modify/add to your source code in break-mode while debugging without having to restart your debugging session. + +This document captures the current state. Potential future improvements in this area are tracked by https://github.com/dotnet/roslyn/issues/49001. **Definitions** * [Variable Capturing](http://blogs.msdn.com/b/matt/archive/2008/03/01/understanding-variable-capturing-in-c.aspx) is the mechanism in which the lambda/delegate which is defined inline is able to hold on to any variables within its lexical scope @@ -12,50 +15,38 @@ Edit & Continue lets you modify/add to your source code in break-mode while debu ### Supported Edits | Edit operation | Additional Info | | ------------------- |--------------------| -| Add methods, fields, constructors, properties, events, indexers, field and property initializers, nested types and top-level types (including delegates, enums, interfaces, abstract and generic types, and anonymous types) to an existing type | The existing type cannot be a generic or an interface.

Adding or modifying [enum members](https://msdn.microsoft.com/en-us/library/sbbt4032.aspx) within an existing enum is not supported. | -| Add and modify iterators | Changing a regular method to an iterator method *is* supported | -| Add async/await expressions | Adding an await expression into an existing async method is not supported.

Adding an await expression around an active statement is not supported.

Changing a regular method to async *is* supported. | -| Modify async/await expressions | Modifying await expressions wrapped inside other expressions (e.g. ```G(await F());```) is not supported | +| Add methods, fields, constructors, properties, events, indexers, field and property initializers, nested types and top-level types (including delegates, enums, interfaces, abstract and generic types, and anonymous types) to an existing type | The existing type cannot be an interface.

Adding or modifying [enum members](https://msdn.microsoft.com/en-us/library/sbbt4032.aspx) within an existing enum is not supported. | +| Add and modify iterators, `yield` statements | Changing a regular method to an iterator method *is* supported | +| Add and modify async methods, `await` expressions | Modifying await expressions wrapped inside other expressions (e.g. ```G(await F());```) is not supported.

Changing a regular method to async *is* supported. | | Add and modify operations with dynamic objects | - | -| Add and modify C# 6.0 language features like string interpolation and null-conditional operators | - | | Add lambda expressions | Lambda expressions can only be added if they are static, access the “this” reference that has already been captured, or access captured variables from a single scope | +| Modify generic code | Enabled in .NET 8 and Visual Studio 17.7 | | Modify lambda expressions | The following rules guarantee that the structure of the emitted closure tree will not change--thus ensuring that lambdas in the new body are mapped to the corresponding generated CLR methods that implemented their previous versions: | | Add LINQ expressions | LINQ expressions contain implicitly-declared anonymous functions. This means the edit rules for lambdas and LINQ will be the same. | | Modify LINQ expressions | LINQ expressions contain implicitly-declared anonymous functions. This means the edit rules for lambdas and LINQ will be the same. | | Modifying async lambda and LINQ expressions in combination | You can edit various nested expressions provided that they otherwise satisfy the EnC rules | -| Edit partial class * | https://docs.microsoft.com/en-us/visualstudio/releases/2019/release-notes#:~:text=it%20is%20now%20possible%20to%20apply%20changes%20in%20code%20that%20is%20within%20a%20partial%20class. | -| Edit Source Generated File * | https://docs.microsoft.com/en-us/visualstudio/releases/2019/release-notes#:~:text=you%20can%20now%20apply%20changes%20within%20a%20source%20generated)%20file. | -| Add using statement * | https://docs.microsoft.com/en-us/visualstudio/releases/2019/release-notes#:~:text=it%20is%20now%20possible%20to%20add%20and%2For%20change%20a%20using%20directive. | - -* = As of Visual Studio 2019 Version 16.10 - - +| Edit partial class | Enabled in [VS 16.10](https://learn.microsoft.com/en-us/visualstudio/releases/2019/release-notes-v16.10) | +| Edit Source Generated File | Enabled in [VS 16.10](https://learn.microsoft.com/en-us/visualstudio/releases/2019/release-notes-v16.10). | +| Add using directive | Enabled in [VS 16.10](https://learn.microsoft.com/en-us/visualstudio/releases/2019/release-notes-v16.10). | +| Deleting members other than fields | Enabled in [VS 17.3](https://learn.microsoft.com/en-us/visualstudio/releases/2022/release-notes-v17.3) | +| Renaming members other than fields | Enabled in [VS 17.4](https://learn.microsoft.com/en-us/visualstudio/releases/2022/release-notes-v17.4) | +| Rename method parameters | Enabled in [VS 17.0](https://learn.microsoft.com/en-us/visualstudio/releases/2022/release-notes-v17.0) | +| Modify method parameter types | Enabled in [VS 17.4](https://learn.microsoft.com/en-us/visualstudio/releases/2022/release-notes-v17.4) | +| Change return type of a method/event/property/operator/indexer | Enabled in [VS 17.4](https://learn.microsoft.com/en-us/visualstudio/releases/2022/release-notes-v17.4) | +| Add and modify custom attributes | Enabled in [VS 17.0](https://learn.microsoft.com/en-us/visualstudio/releases/2022/release-notes-v17.0) | +| Adding and modifying namespace declarations | Enabled in [VS 17.3](https://learn.microsoft.com/en-us/visualstudio/releases/2022/release-notes-v17.3) | ### Not Supported Edits | Edit operation | Additional Info | | ------------------- |-----------------| -| Modify [method signatures](https://msdn.microsoft.com/en-us/library/ms173114.aspx) | - | -| Add or modify [generics](https://msdn.microsoft.com/en-us/library/512aeb7t.aspx) | - | | Modify interfaces | - | | Add a method body such that an abstract method becomes non-abstract | - | | Add new abstract, virtual, or override member to a type | You CAN add a non-abstract member to an abstract type | | Add [destructor](https://msdn.microsoft.com/en-us/library/66x5fx1b.aspx) to an existing type | - | -| Modify a type parameter, base type, delegate type, or return type of an event/property/operator/indexer | - | +| Modify a type parameter, base type, delegate type | - | | Modify a catch-block if it contains an active statement (leaf or internal) | - | | Modify a try-catch-finally block if the finally clause contains an active statement | - | -| Renaming of any kind | - | -| Delete members, types, namespaces | - | -| Delete entire method bodies | Not supported because deleting an entire method body would make the method “abstract”—which is not currently supported | -| Add using statements | Allowed in Visual Studio 2019 Version 16.10 | -| Add a namespace | - | +| Delete types | - | | Edit a member referencing an embedded interop type | - | | Edit a member with On Error or Resume statements | Specific to Visual Basic | | Edit a member containing an Aggregate, Group By, Simple Join, or Group Join LINQ query clause | Specific to Visual Basic | -| Edit an async method/lambda in a project that doesn't define or reference AsyncStateMachineAttribute type (e.g. projects targeting .NET Framework 4.0 and lower) | - | -| Edit an iterator method/lambda in a project that doesn't define or reference IteratorStateMachineAttribute type (e.g. projects targeting .NET Framework 4.0 and lower) | - | - -### App Model EnC Support - -| Support EnC | Do Not Support EnC | -| ------------------ |------------------------------| -|