diff --git a/Directory.Build.props b/Directory.Build.props index d212ce253ae..643c0267e79 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -174,7 +174,6 @@ $([MSBuild]::NormalizeDirectory('$(PrereqsPackagesDir)', 'previously-source-built')) $([MSBuild]::EnsureTrailingSlash('$(CustomPreviouslySourceBuiltPackagesPath)')) - $([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'prebuilt-report')) $([MSBuild]::NormalizeDirectory('$(SrcDir)', 'source-build-reference-packages', 'src')) $([MSBuild]::NormalizeDirectory('$(PrereqsPackagesDir)', 'reference')) SourceBuildReferencePackages diff --git a/docs/builds-table.md b/docs/builds-table.md index be5c9922788..63e5033061f 100644 --- a/docs/builds-table.md +++ b/docs/builds-table.md @@ -2,19 +2,19 @@ -------------------------------------------------------------------------------------- -| Platform | main
(10.0.x Runtime) | -| :--------- | :----------: | -| **Windows x64** | [![][win-x64-badge-main]][win-x64-version-main]
[Installer][win-x64-installer-main] - [Checksum][win-x64-installer-checksum-main]
[zip][win-x64-zip-main] - [Checksum][win-x64-zip-checksum-main] | -| **Windows x86** | [![][win-x86-badge-main]][win-x86-version-main]
[Installer][win-x86-installer-main] - [Checksum][win-x86-installer-checksum-main]
[zip][win-x86-zip-main] - [Checksum][win-x86-zip-checksum-main] | -| **Windows arm64** | [![][win-arm64-badge-main]][win-arm64-version-main]
[Installer][win-arm64-installer-main] - [Checksum][win-arm64-installer-checksum-main]
[zip][win-arm64-zip-main] - [Checksum][win-arm64-zip-checksum-main] | -| **macOS x64** | [![][osx-x64-badge-main]][osx-x64-version-main]
[Installer][osx-x64-installer-main] - [Checksum][osx-x64-installer-checksum-main]
[tar.gz][osx-x64-targz-main] - [Checksum][osx-x64-targz-checksum-main] | -| **macOS arm64** | [![][osx-arm64-badge-main]][osx-arm64-version-main]
[Installer][osx-arm64-installer-main] - [Checksum][osx-arm64-installer-checksum-main]
[tar.gz][osx-arm64-targz-main] - [Checksum][osx-arm64-targz-checksum-main] | -| **Linux x64** | [![][linux-badge-main]][linux-version-main]
[DEB Installer][linux-DEB-installer-main] - [Checksum][linux-DEB-installer-checksum-main]
[RPM Installer][linux-RPM-installer-main] - [Checksum][linux-RPM-installer-checksum-main]
_see installer note below_1
[tar.gz][linux-targz-main] - [Checksum][linux-targz-checksum-main] | -| **Linux arm** | [![][linux-arm-badge-main]][linux-arm-version-main]
[tar.gz][linux-arm-targz-main] - [Checksum][linux-arm-targz-checksum-main] | -| **Linux arm64** | [![][linux-arm64-badge-main]][linux-arm64-version-main]
[tar.gz][linux-arm64-targz-main] - [Checksum][linux-arm64-targz-checksum-main] | -| **Linux-musl-x64** | [![][linux-musl-x64-badge-main]][linux-musl-x64-version-main]
[tar.gz][linux-musl-x64-targz-main] - [Checksum][linux-musl-x64-targz-checksum-main] | -| **Linux-musl-arm** | [![][linux-musl-arm-badge-main]][linux-musl-arm-version-main]
[tar.gz][linux-musl-arm-targz-main] - [Checksum][linux-musl-arm-targz-checksum-main] | -| **Linux-musl-arm64** | [![][linux-musl-arm64-badge-main]][linux-musl-arm64-version-main]
[tar.gz][linux-musl-arm64-targz-main] - [Checksum][linux-musl-arm64-targz-checksum-main] | +| Platform | main
(10.0.x Runtime) | 10.0.1xx-preview4
(10.0-preview4 Runtime) | +| :--------- | :----------: | :----------: | +| **Windows x64** | [![][win-x64-badge-main]][win-x64-version-main]
[Installer][win-x64-installer-main] - [Checksum][win-x64-installer-checksum-main]
[zip][win-x64-zip-main] - [Checksum][win-x64-zip-checksum-main] | [![][win-x64-badge-10.0.1XX-preview4]][win-x64-version-10.0.1XX-preview4]
[Installer][win-x64-installer-10.0.1XX-preview4] - [Checksum][win-x64-installer-checksum-10.0.1XX-preview4]
[zip][win-x64-zip-10.0.1XX-preview4] - [Checksum][win-x64-zip-checksum-10.0.1XX-preview4] | +| **Windows x86** | [![][win-x86-badge-main]][win-x86-version-main]
[Installer][win-x86-installer-main] - [Checksum][win-x86-installer-checksum-main]
[zip][win-x86-zip-main] - [Checksum][win-x86-zip-checksum-main] | [![][win-x86-badge-10.0.1XX-preview4]][win-x86-version-10.0.1XX-preview4]
[Installer][win-x86-installer-10.0.1XX-preview4] - [Checksum][win-x86-installer-checksum-10.0.1XX-preview4]
[zip][win-x86-zip-10.0.1XX-preview4] - [Checksum][win-x86-zip-checksum-10.0.1XX-preview4] | +| **Windows arm64** | [![][win-arm64-badge-main]][win-arm64-version-main]
[Installer][win-arm64-installer-main] - [Checksum][win-arm64-installer-checksum-main]
[zip][win-arm64-zip-main] - [Checksum][win-arm64-zip-checksum-main] | [![][win-arm64-badge-10.0.1XX-preview4]][win-arm64-version-10.0.1XX-preview4]
[Installer][win-arm64-installer-10.0.1XX-preview4] - [Checksum][win-arm64-installer-checksum-10.0.1XX-preview4]
[zip][win-arm64-zip-10.0.1XX-preview4] | +| **macOS x64** | [![][osx-x64-badge-main]][osx-x64-version-main]
[Installer][osx-x64-installer-main] - [Checksum][osx-x64-installer-checksum-main]
[tar.gz][osx-x64-targz-main] - [Checksum][osx-x64-targz-checksum-main] | [![][osx-x64-badge-10.0.1XX-preview4]][osx-x64-version-10.0.1XX-preview4]
[Installer][osx-x64-installer-10.0.1XX-preview4] - [Checksum][osx-x64-installer-checksum-10.0.1XX-preview4]
[tar.gz][osx-x64-targz-10.0.1XX-preview4] - [Checksum][osx-x64-targz-checksum-10.0.1XX-preview4] | +| **macOS arm64** | [![][osx-arm64-badge-main]][osx-arm64-version-main]
[Installer][osx-arm64-installer-main] - [Checksum][osx-arm64-installer-checksum-main]
[tar.gz][osx-arm64-targz-main] - [Checksum][osx-arm64-targz-checksum-main] | [![][osx-arm64-badge-10.0.1XX-preview4]][osx-arm64-version-10.0.1XX-preview4]
[Installer][osx-arm64-installer-10.0.1XX-preview4] - [Checksum][osx-arm64-installer-checksum-10.0.1XX-preview4]
[tar.gz][osx-arm64-targz-10.0.1XX-preview4] - [Checksum][osx-arm64-targz-checksum-10.0.1XX-preview4] | +| **Linux x64** | [![][linux-badge-main]][linux-version-main]
[DEB Installer][linux-DEB-installer-main] - [Checksum][linux-DEB-installer-checksum-main]
[RPM Installer][linux-RPM-installer-main] - [Checksum][linux-RPM-installer-checksum-main]
_see installer note below_1
[tar.gz][linux-targz-main] - [Checksum][linux-targz-checksum-main] | [![][linux-badge-10.0.1XX-preview4]][linux-version-10.0.1XX-preview4]
[DEB Installer][linux-DEB-installer-10.0.1XX-preview4] - [Checksum][linux-DEB-installer-checksum-10.0.1XX-preview4]
[RPM Installer][linux-RPM-installer-10.0.1XX-preview4] - [Checksum][linux-RPM-installer-checksum-10.0.1XX-preview4]
_see installer note below_1
[tar.gz][linux-targz-10.0.1XX-preview4] - [Checksum][linux-targz-checksum-10.0.1XX-preview4] | +| **Linux arm** | [![][linux-arm-badge-main]][linux-arm-version-main]
[tar.gz][linux-arm-targz-main] - [Checksum][linux-arm-targz-checksum-main] | [![][linux-arm-badge-10.0.1XX-preview4]][linux-arm-version-10.0.1XX-preview4]
[tar.gz][linux-arm-targz-10.0.1XX-preview4] - [Checksum][linux-arm-targz-checksum-10.0.1XX-preview4] | +| **Linux arm64** | [![][linux-arm64-badge-main]][linux-arm64-version-main]
[tar.gz][linux-arm64-targz-main] - [Checksum][linux-arm64-targz-checksum-main] | [![][linux-arm64-badge-10.0.1XX-preview4]][linux-arm64-version-10.0.1XX-preview4]
[tar.gz][linux-arm64-targz-10.0.1XX-preview4] - [Checksum][linux-arm64-targz-checksum-10.0.1XX-preview4] | +| **Linux-musl-x64** | [![][linux-musl-x64-badge-main]][linux-musl-x64-version-main]
[tar.gz][linux-musl-x64-targz-main] - [Checksum][linux-musl-x64-targz-checksum-main] | [![][linux-musl-x64-badge-10.0.1XX-preview4]][linux-musl-x64-version-10.0.1XX-preview4]
[tar.gz][linux-musl-x64-targz-10.0.1XX-preview4] - [Checksum][linux-musl-x64-targz-checksum-10.0.1XX-preview4] | +| **Linux-musl-arm** | [![][linux-musl-arm-badge-main]][linux-musl-arm-version-main]
[tar.gz][linux-musl-arm-targz-main] - [Checksum][linux-musl-arm-targz-checksum-main] | [![][linux-musl-arm-badge-10.0.1XX-preview4]][linux-musl-arm-version-10.0.1XX-preview4]
[tar.gz][linux-musl-arm-targz-10.0.1XX-preview4] - [Checksum][linux-musl-arm-targz-checksum-10.0.1XX-preview4] | +| **Linux-musl-arm64** | [![][linux-musl-arm64-badge-main]][linux-musl-arm64-version-main]
[tar.gz][linux-musl-arm64-targz-main] - [Checksum][linux-musl-arm64-targz-checksum-main] | [![][linux-musl-arm64-badge-10.0.1XX-preview4]][linux-musl-arm64-version-10.0.1XX-preview4]
[tar.gz][linux-musl-arm64-targz-10.0.1XX-preview4] - [Checksum][linux-musl-arm64-targz-checksum-10.0.1XX-preview4] | Reference notes: > **1**: Our Debian packages are put together slightly differently than the other OS specific installers. Instead of combining everything, we have separate component packages that depend on each other. If you're installing the SDK from the .deb file (via dpkg or similar), then you'll need to install the corresponding dependencies first: @@ -28,6 +28,13 @@ Reference notes: [win-x64-zip-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-win-x64.zip [win-x64-zip-checksum-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-win-x64.zip.sha512 +[win-x64-badge-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/win_x64_Release_version_badge.svg?no-cache +[win-x64-version-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/productCommit-win-x64.txt +[win-x64-installer-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-win-x64.exe +[win-x64-installer-checksum-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-win-x64.exe.sha512 +[win-x64-zip-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-win-x64.zip +[win-x64-zip-checksum-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-win-x64.zip.sha512 + [win-x86-badge-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/win_x86_Release_version_badge.svg?no-cache [win-x86-version-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/productCommit-win-x86.txt [win-x86-installer-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-win-x86.exe @@ -35,6 +42,13 @@ Reference notes: [win-x86-zip-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-win-x86.zip [win-x86-zip-checksum-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-win-x86.zip.sha512 +[win-x86-badge-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/win_x86_Release_version_badge.svg?no-cache +[win-x86-version-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/productCommit-win-x86.txt +[win-x86-installer-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-win-x86.exe +[win-x86-installer-checksum-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-win-x86.exe.sha512 +[win-x86-zip-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-win-x86.zip +[win-x86-zip-checksum-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-win-x86.zip.sha512 + [osx-x64-badge-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/osx_x64_Release_version_badge.svg?no-cache [osx-x64-version-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/productCommit-osx-x64.txt [osx-x64-installer-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-osx-x64.pkg @@ -42,6 +56,13 @@ Reference notes: [osx-x64-targz-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-osx-x64.tar.gz [osx-x64-targz-checksum-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-osx-x64.pkg.tar.gz.sha512 +[osx-x64-badge-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/osx_x64_Release_version_badge.svg?no-cache +[osx-x64-version-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/productCommit-osx-x64.txt +[osx-x64-installer-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-osx-x64.pkg +[osx-x64-installer-checksum-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-osx-x64.pkg.sha512 +[osx-x64-targz-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-osx-x64.tar.gz +[osx-x64-targz-checksum-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-osx-x64.pkg.tar.gz.sha512 + [osx-arm64-badge-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/osx_arm64_Release_version_badge.svg?no-cache [osx-arm64-version-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/productCommit-osx-arm64.txt [osx-arm64-installer-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-osx-arm64.pkg @@ -49,6 +70,13 @@ Reference notes: [osx-arm64-targz-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-osx-arm64.tar.gz [osx-arm64-targz-checksum-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-osx-arm64.pkg.tar.gz.sha512 +[osx-arm64-badge-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/osx_arm64_Release_version_badge.svg?no-cache +[osx-arm64-version-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/productCommit-osx-arm64.txt +[osx-arm64-installer-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-osx-arm64.pkg +[osx-arm64-installer-checksum-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-osx-arm64.pkg.sha512 +[osx-arm64-targz-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-osx-arm64.tar.gz +[osx-arm64-targz-checksum-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-osx-arm64.pkg.tar.gz.sha512 + [linux-badge-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/linux_x64_Release_version_badge.svg?no-cache [linux-version-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/productCommit-linux-x64.txt [linux-DEB-installer-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-x64.deb @@ -58,39 +86,75 @@ Reference notes: [linux-targz-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-linux-x64.tar.gz [linux-targz-checksum-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-linux-x64.tar.gz.sha512 +[linux-badge-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/linux_x64_Release_version_badge.svg?no-cache +[linux-version-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/productCommit-linux-x64.txt +[linux-DEB-installer-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-x64.deb +[linux-DEB-installer-checksum-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-x64.deb.sha512 +[linux-RPM-installer-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-x64.rpm +[linux-RPM-installer-checksum-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-x64.rpm.sha512 +[linux-targz-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-linux-x64.tar.gz +[linux-targz-checksum-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-linux-x64.tar.gz.sha512 + [linux-arm-badge-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/linux_arm_Release_version_badge.svg?no-cache [linux-arm-version-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/productCommit-linux-arm.txt [linux-arm-targz-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-linux-arm.tar.gz [linux-arm-targz-checksum-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-linux-arm.tar.gz.sha512 +[linux-arm-badge-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/linux_arm_Release_version_badge.svg?no-cache +[linux-arm-version-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/productCommit-linux-arm.txt +[linux-arm-targz-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-linux-arm.tar.gz +[linux-arm-targz-checksum-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-linux-arm.tar.gz.sha512 + [linux-arm64-badge-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/linux_arm64_Release_version_badge.svg?no-cache [linux-arm64-version-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/productCommit-linux-arm64.txt [linux-arm64-targz-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-linux-arm64.tar.gz [linux-arm64-targz-checksum-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-linux-arm64.tar.gz.sha512 -[rhel-6-badge-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/rhel.6_x64_Release_version_badge.svg?no-cache -[rhel-6-version-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/productCommit-rhel.6-x64.txt -[rhel-6-targz-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-rhel.6-x64.tar.gz -[rhel-6-targz-checksum-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-rhel.6-x64.tar.gz.sha512 +[linux-arm64-badge-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/linux_arm64_Release_version_badge.svg?no-cache +[linux-arm64-version-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/productCommit-linux-arm64.txt +[linux-arm64-targz-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-linux-arm64.tar.gz +[linux-arm64-targz-checksum-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-linux-arm64.tar.gz.sha512 [linux-musl-x64-badge-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/linux_musl_x64_Release_version_badge.svg?no-cache [linux-musl-x64-version-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/productCommit-linux-musl-x64.txt [linux-musl-x64-targz-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-linux-musl-x64.tar.gz [linux-musl-x64-targz-checksum-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-linux-musl-x64.tar.gz.sha512 +[linux-musl-x64-badge-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/linux_musl_x64_Release_version_badge.svg?no-cache +[linux-musl-x64-version-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/productCommit-linux-musl-x64.txt +[linux-musl-x64-targz-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-linux-musl-x64.tar.gz +[linux-musl-x64-targz-checksum-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-linux-musl-x64.tar.gz.sha512 + [linux-musl-arm-badge-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/linux_musl_arm_Release_version_badge.svg?no-cache [linux-musl-arm-version-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/productCommit-linux-musl-arm.txt [linux-musl-arm-targz-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-linux-musl-arm.tar.gz [linux-musl-arm-targz-checksum-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-linux-musl-arm.tar.gz.sha512 +[linux-musl-arm-badge-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/linux_musl_arm_Release_version_badge.svg?no-cache +[linux-musl-arm-version-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/productCommit-linux-musl-arm.txt +[linux-musl-arm-targz-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-linux-musl-arm.tar.gz +[linux-musl-arm-targz-checksum-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-linux-musl-arm.tar.gz.sha512 + [linux-musl-arm64-badge-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/linux_musl_arm64_Release_version_badge.svg?no-cache [linux-musl-arm64-version-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/productCommit-linux-musl-arm64.txt [linux-musl-arm64-targz-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-linux-musl-arm64.tar.gz [linux-musl-arm64-targz-checksum-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-linux-musl-arm64.tar.gz.sha512 +[linux-musl-arm64-badge-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/linux_musl_arm64_Release_version_badge.svg?no-cache +[linux-musl-arm64-version-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/productCommit-linux-musl-arm64.txt +[linux-musl-arm64-targz-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-linux-musl-arm64.tar.gz +[linux-musl-arm64-targz-checksum-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-linux-musl-arm64.tar.gz.sha512 + [win-arm64-badge-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/win_arm64_Release_version_badge.svg?no-cache [win-arm64-version-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/productCommit-win-arm64.txt [win-arm64-installer-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-win-arm64.exe [win-arm64-installer-checksum-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-win-arm64.exe.sha512 [win-arm64-zip-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-win-arm64.zip -[win-arm64-zip-checksum-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-win-arm64.zip.sha512 \ No newline at end of file +[win-arm64-zip-checksum-main]: https://aka.ms/dotnet/10.0.1xx-ub/daily/dotnet-sdk-win-arm64.zip.sha512 + +[win-arm64-badge-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/win_arm64_Release_version_badge.svg?no-cache +[win-arm64-version-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/productCommit-win-arm64.txt +[win-arm64-installer-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-win-arm64.exe +[win-arm64-installer-checksum-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-win-arm64.exe.sha512 +[win-arm64-zip-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-win-arm64.zip +[win-arm64-zip-checksum-10.0.1XX-preview4]: https://aka.ms/dotnet/10.0.1xx-preview4/daily/dotnet-sdk-win-arm64.zip.sha512 \ No newline at end of file diff --git a/eng/pipelines/templates/stages/source-build-and-validate.yml b/eng/pipelines/templates/stages/source-build-and-validate.yml index 21a793575db..746da15d085 100644 --- a/eng/pipelines/templates/stages/source-build-and-validate.yml +++ b/eng/pipelines/templates/stages/source-build-and-validate.yml @@ -219,8 +219,8 @@ stages: - template: ../steps/download-artifacts.yml parameters: artifactDescription: Source Build Poison Report - downloadFilePatterns: BuildLogs/artifacts/prebuilt-report/poison-usage.xml - copyDestination: $(Build.SourcesDirectory)/artifacts/prebuilt-report + downloadFilePatterns: BuildLogs/artifacts/log/Release/poison-usage.xml + copyDestination: $(Build.SourcesDirectory)/artifacts/log/Release flattenDirs: true ${{ if eq(leg.distro, 'centos') }}: artifactName: ${{ format(leg.buildNameFormat, variables.centOSStreamName) }}_${{ leg.targetArchitecture}}_Artifacts diff --git a/prereqs/git-info/arcade.props b/prereqs/git-info/arcade.props index 8d347dbd5dd..8e26afe0122 100644 --- a/prereqs/git-info/arcade.props +++ b/prereqs/git-info/arcade.props @@ -1,8 +1,8 @@  - f351706234bfbdf026577122a3f2bac65eb74a5b - 20250430.3 - 10.0.0-beta.25230.3 + cdf9c563205c673b7df205e24564aa48dbc341c3 + 20250503.1 + 10.0.0-beta.25253.1 \ No newline at end of file diff --git a/prereqs/git-info/aspnetcore.props b/prereqs/git-info/aspnetcore.props index d6ddf0b1696..205cb813083 100644 --- a/prereqs/git-info/aspnetcore.props +++ b/prereqs/git-info/aspnetcore.props @@ -1,8 +1,8 @@  - 21ba24a7015eee34b6879b4fd2f0b94b5ff8faa6 - 20250430.1 - 10.0.0-preview.5.25230.1 + b9112907bd7526126a355a895cce9d1ffc8bdc85 + 20250505.2 + 10.0.0-preview.5.25255.2 \ No newline at end of file diff --git a/prereqs/git-info/cecil.props b/prereqs/git-info/cecil.props index fa78d329b2b..9c071741636 100644 --- a/prereqs/git-info/cecil.props +++ b/prereqs/git-info/cecil.props @@ -1,8 +1,8 @@  - 8f5ef5bf825aed91bb15039b02f7426f165b5eb8 - 20250501.1 - 0.11.5-alpha.25251.1 + ace481b2c118341192e9ac0caceb17cede03ed47 + 20250502.1 + 0.11.5-alpha.25252.1 \ No newline at end of file diff --git a/prereqs/git-info/command-line-api.props b/prereqs/git-info/command-line-api.props index ec987f60079..4f7212682c7 100644 --- a/prereqs/git-info/command-line-api.props +++ b/prereqs/git-info/command-line-api.props @@ -1,8 +1,8 @@  - e5a8d8400751a0fe40f766f2130ef00c59ee9c56 - 20250501.4 - 0.1.625104 + c07f759f70b5517a7fefb9ac5ac73603cff49f41 + 20250502.1 + 0.1.625201 \ No newline at end of file diff --git a/prereqs/git-info/deployment-tools.props b/prereqs/git-info/deployment-tools.props index 40dbd8c76c4..004b08d02a8 100644 --- a/prereqs/git-info/deployment-tools.props +++ b/prereqs/git-info/deployment-tools.props @@ -1,8 +1,8 @@  - 150d38efe20041a832482eb69e0d61b5d795e167 - 20250501.1 - 9.0.0-preview.1.25251.1 + 6b4bb9fae2d5c2caa1c5da1b49a045239bbbae3a + 20250505.1 + 9.0.0-preview.1.25255.1 \ No newline at end of file diff --git a/prereqs/git-info/diagnostics.props b/prereqs/git-info/diagnostics.props index 9705f2c14b0..f5af1c59a62 100644 --- a/prereqs/git-info/diagnostics.props +++ b/prereqs/git-info/diagnostics.props @@ -1,8 +1,8 @@  - c174aba9f07ab60c9dc4a68080988e5fd411afea - 20250430.3 - 9.0.623003 + 8a951ade8ae70e5fc47345958cf716cc8e9cffe5 + 20250505.1 + 9.0.625501 \ No newline at end of file diff --git a/prereqs/git-info/efcore.props b/prereqs/git-info/efcore.props index 289ac8ac001..b8ea62616d4 100644 --- a/prereqs/git-info/efcore.props +++ b/prereqs/git-info/efcore.props @@ -1,8 +1,8 @@  - 4ff9270f21135dba86d678b8515ed2ba2e15089d - 20250501.4 - 10.0.0-preview.5.25251.4 + 9b42f3657525ea451573d241c86d09f5b08fe6dd + 20250505.1 + 10.0.0-preview.5.25255.1 \ No newline at end of file diff --git a/prereqs/git-info/emsdk.props b/prereqs/git-info/emsdk.props index dc5393765e9..be6bbf681bb 100644 --- a/prereqs/git-info/emsdk.props +++ b/prereqs/git-info/emsdk.props @@ -1,8 +1,8 @@  - 90489ef36c66f4d57ddcc077429699e313eb8d05 - 20250424.1 - 10.0.0-preview.5.25224.1 + ec33d78d8515c08b528f10ffd9da3b0ed267a89c + 20250505.1 + 10.0.0-preview.5.25255.1 \ No newline at end of file diff --git a/prereqs/git-info/msbuild.props b/prereqs/git-info/msbuild.props index 979d297f98c..5babe043907 100644 --- a/prereqs/git-info/msbuild.props +++ b/prereqs/git-info/msbuild.props @@ -1,8 +1,8 @@  - 4775228475c3d687559252223447d94194dd0f5f - 20250430.2 - 17.15.0-preview-25230-02 + 17a2cd4231cf3c198aa09d1000b4340e2f6bfd20 + 20250505.5 + 17.15.0-preview-25255-05 \ No newline at end of file diff --git a/prereqs/git-info/nuget-client.props b/prereqs/git-info/nuget-client.props index 322994843a9..064bf737143 100644 --- a/prereqs/git-info/nuget-client.props +++ b/prereqs/git-info/nuget-client.props @@ -1,8 +1,8 @@  - 86c695c5bdd02ca0aa735eed42508b57f695baa7 - 6.15.0.31 - 6.15.0-preview.1.31 + 41fb88a624e61dce1fa05a5d0771b41ab7aff7a9 + 6.15.0.37 + 6.15.0-preview.1.37 \ No newline at end of file diff --git a/prereqs/git-info/razor.props b/prereqs/git-info/razor.props index 56eb9919142..ecdfaac62e0 100644 --- a/prereqs/git-info/razor.props +++ b/prereqs/git-info/razor.props @@ -1,8 +1,8 @@  - 2e057fe832fbda6847f68d5782508d6c469d794c - 20250501.3 - 10.0.0-preview.25251.3 + d87bf4a7f18d1bdfd14cc0964acdf9b5bada301c + 20250505.5 + 10.0.0-preview.25255.5 \ No newline at end of file diff --git a/prereqs/git-info/roslyn-analyzers.props b/prereqs/git-info/roslyn-analyzers.props index 70ba222140a..f8799477d57 100644 --- a/prereqs/git-info/roslyn-analyzers.props +++ b/prereqs/git-info/roslyn-analyzers.props @@ -1,8 +1,8 @@  - a5c872bfda401e95a51628f961fb5abc2d182e73 - 20250425.1 - 10.0.0-preview.25225.1 + ba7afc0f470c9b92b88c9468420942b2d1d57355 + 20250429.1 + 10.0.0-preview.25229.1 \ No newline at end of file diff --git a/prereqs/git-info/roslyn.props b/prereqs/git-info/roslyn.props index 9672f00df23..1cf150eb2f6 100644 --- a/prereqs/git-info/roslyn.props +++ b/prereqs/git-info/roslyn.props @@ -1,8 +1,8 @@  - ded867328249b5a9b9e6e29e3f07abc19111f5d1 - 20250430.6 - 5.0.0-1.25230.6 + 9cce7288b4f277359e40488eacc1bd8be0f81f34 + 20250505.5 + 5.0.0-1.25255.5 \ No newline at end of file diff --git a/prereqs/git-info/runtime.props b/prereqs/git-info/runtime.props index 284dff843ae..bef7cbd2dfc 100644 --- a/prereqs/git-info/runtime.props +++ b/prereqs/git-info/runtime.props @@ -1,8 +1,8 @@  - 27604b57bd2e9c9aa46d005db7c4e387d461b5b6 - 20250501.7 - 10.0.0-preview.5.25251.7 + 43955cb086eb88dbe78f1764c21dd3362a2427ee + 20250505.1 + 10.0.0-preview.5.25255.1 \ No newline at end of file diff --git a/prereqs/git-info/scenario-tests.props b/prereqs/git-info/scenario-tests.props index 5fbc39e63c4..0d8908583ce 100644 --- a/prereqs/git-info/scenario-tests.props +++ b/prereqs/git-info/scenario-tests.props @@ -1,8 +1,8 @@  - da2163776e83f86ea1259ce9e12b9ea48db6ab60 - 20250429.1 + 9eabbcd6e92c63e0539a649238e5a87d73f46065 + 20250505.3 10.0.0-preview.25221.1 \ No newline at end of file diff --git a/prereqs/git-info/sdk.props b/prereqs/git-info/sdk.props index 7c58cc4ca62..a9de99976f2 100644 --- a/prereqs/git-info/sdk.props +++ b/prereqs/git-info/sdk.props @@ -1,8 +1,8 @@  - 7601b9cae2f49701609df537fe81ae73425109ed - 20250501.4 - 10.0.100-preview.5.25251.4 + 86317d70a92223dff361e28d2874188219c7560b + 20250505.3 + 10.0.100-preview.5.25255.3 \ No newline at end of file diff --git a/prereqs/git-info/source-build-externals.props b/prereqs/git-info/source-build-externals.props index 54df22f9045..e804bb0c9ed 100644 --- a/prereqs/git-info/source-build-externals.props +++ b/prereqs/git-info/source-build-externals.props @@ -1,8 +1,8 @@  - 37a16c719922cb4203d0506484502fd62ac91aa7 - 20250428.1 + 967f0738ad131b3cb0b76b112618923780aa6048 + 20250505.4 10.0.622801 \ No newline at end of file diff --git a/prereqs/git-info/source-build-reference-packages.props b/prereqs/git-info/source-build-reference-packages.props index 01f85e6fe51..b6e9682a0bc 100644 --- a/prereqs/git-info/source-build-reference-packages.props +++ b/prereqs/git-info/source-build-reference-packages.props @@ -1,8 +1,8 @@  - d1ab3b44c05f314be6885d1933d7e48fffa0cfc2 - 20250501.1 + e6e60523801abc7c581434b4cd7ba1f8ee34347c + 20250505.2 \ No newline at end of file diff --git a/prereqs/git-info/sourcelink.props b/prereqs/git-info/sourcelink.props index 667fe10d29e..bc305a69d0b 100644 --- a/prereqs/git-info/sourcelink.props +++ b/prereqs/git-info/sourcelink.props @@ -1,8 +1,8 @@  - 25716402f74dfeb1f4137601d013e158628d5196 - 20250501.2 - 10.0.0-beta.25251.2 + d6ff9e72e3a48d39b19a1b2d7cbf63a0a79a6409 + 20250502.2 + 10.0.0-beta.25252.2 \ No newline at end of file diff --git a/prereqs/git-info/templating.props b/prereqs/git-info/templating.props index 7b443e349f8..c8d099d53a4 100644 --- a/prereqs/git-info/templating.props +++ b/prereqs/git-info/templating.props @@ -1,8 +1,8 @@  - 03eef3b9429ba0975982ca7427274e5986ef328e - 20250501.2 - 10.0.100-preview.5.25251.2 + e3f1cf05499c250de847205b51d31a5d1f7639c4 + 20250505.1 + 10.0.100-preview.5.25255.1 \ No newline at end of file diff --git a/prereqs/git-info/windowsdesktop.props b/prereqs/git-info/windowsdesktop.props index 0f6ce4308a4..162e9d1fa15 100644 --- a/prereqs/git-info/windowsdesktop.props +++ b/prereqs/git-info/windowsdesktop.props @@ -1,8 +1,8 @@  - 2ebb7d189eccf908c7121a5c1e5e71da0085c4dc - 20250501.1 - 10.0.0-preview.5.25251.1 + b88bee3ab8a7ba608d792d30c30dda3366044eec + 20250502.1 + 10.0.0-preview.5.25252.1 \ No newline at end of file diff --git a/prereqs/git-info/winforms.props b/prereqs/git-info/winforms.props index af62b9f81d2..20a2ea8b921 100644 --- a/prereqs/git-info/winforms.props +++ b/prereqs/git-info/winforms.props @@ -1,8 +1,8 @@  - 43ffa433a31ca3a6af20cefadf2b13ba2a7e537d - 20250501.4 - 10.0.0-preview.5.25251.4 + fc5d461e63815788594bcfd7c35ace5c0958b7bc + 20250505.1 + 10.0.0-preview.5.25255.1 \ No newline at end of file diff --git a/prereqs/git-info/wpf.props b/prereqs/git-info/wpf.props index aa66b7b377a..d68ced53057 100644 --- a/prereqs/git-info/wpf.props +++ b/prereqs/git-info/wpf.props @@ -1,8 +1,8 @@  - 53aa6f986b8c1f84cf58dbd6ea62b363f94a939d - 20250429.1 - 10.0.0-preview.5.25229.1 + e188e3587630e370a711fe9566a9011a7c5a181b + 20250505.1 + 10.0.0-preview.5.25255.1 \ No newline at end of file diff --git a/repo-projects/Directory.Build.props b/repo-projects/Directory.Build.props index c17a695a8cc..3b45fd206db 100644 --- a/repo-projects/Directory.Build.props +++ b/repo-projects/Directory.Build.props @@ -49,7 +49,7 @@ $([MSBuild]::NormalizeDirectory('$(AssetManifestsIntermediateDir)', '$(RepositoryName)')) $([MSBuild]::NormalizeDirectory('$(ProjectDirectory)', 'artifacts')) - $([MSBuild]::NormalizeDirectory('$(RepoArtifactsDir)', 'sb', 'package-cache')) + $([MSBuild]::NormalizeDirectory('$(RepoArtifactsDir)', '.packages')) $([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'source-built-sdks')) @@ -112,10 +112,7 @@ $(CommonArgs) $(FlagParameterPrefix)configuration $(Configuration) - - $(CommonArgs) $(FlagParameterPrefix)verbosity $(LogVerbosity) + $(CommonArgs) $(FlagParameterPrefix)verbosity $(LogVerbosity) $(CommonArgs) /p:TargetRid=$(TargetRid) @@ -127,12 +124,20 @@ $(CommonArgs) /p:OfficialBuildId=$(OfficialBuildId) $(CommonArgs) /p:OfficialBuilder=$(OfficialBuilder) $(CommonArgs) /p:ForceDryRunSigning=$(ForceDryRunSigning) + + $(CommonArgs) /p:UseArPowBuildInfra=false $(CommonArgs) /p:SourceBuiltAssetsDir=$(ArtifactsAssetsDir) $(CommonArgs) /p:SourceBuiltAssetManifestsDir=$(RepoAssetManifestsDir) $(CommonArgs) /p:GitHubRepositoryName=$(RepositoryName) + $(CommonArgs) /p:DotNetBuildRepo=true + $(CommonArgs) /p:DotNetBuildOrchestrator=true + + + https://github.com/dotnet/dotnet + $(CommonArgs) /p:RepositoryUrl=$(DotNetRepositoryUrl) Vertical @@ -140,21 +145,16 @@ Vertical + + $(CommonArgs) /p:DotNetBuildSourceOnly=true + $(CommonArgs) /p:PreviouslySourceBuiltNupkgCacheDir="$(PreviouslySourceBuiltPackagesPath)" + $(CommonArgs) /p:ReferencePackageNupkgCacheDir="$(ReferencePackagesDir)" + $(CommonArgs) /p:PrebuiltUsageReportDir="$(ArtifactsLogRepoDir)" + + $(BuildArgs) -bl - - $(BuildArgs) /p:DotNetBuildRepo=true - $(BuildArgs) /p:DotNetBuildOrchestrator=true - - https://github.com/dotnet/dotnet - $(BuildArgs) /p:RepositoryUrl=$(DotNetRepositoryUrl) - - - $(BuildArgs) /p:DotNetBuildSourceOnly=true - $(BuildArgs) /p:PreviouslySourceBuiltNupkgCacheDir="$(PreviouslySourceBuiltPackagesPath)" - $(BuildArgs) /p:ReferencePackageNupkgCacheDir="$(ReferencePackagesDir)" - $(BuildArgs) /p:SourceBuildPrebuiltReportDir="$(ArtifactsLogRepoDir)" diff --git a/repo-projects/Directory.Build.targets b/repo-projects/Directory.Build.targets index 39a1eb7e66e..666a1449faa 100644 --- a/repo-projects/Directory.Build.targets +++ b/repo-projects/Directory.Build.targets @@ -2,12 +2,6 @@ - - $(CommonArgs) /p:UseInnerClone=true - $(CommonArgs) /p:CopySrcInsteadOfClone=true - $(CommonArgs) /p:CopyWipIntoInnerSourceBuildRepo=true - - powershell -NoProfile "Get-PSDrive -PSProvider FileSystem -Name (Get-Item "$(RepoRoot.TrimEnd('\'))").PSDrive.Name" df -h $(RepoRoot) @@ -700,8 +694,7 @@ Condition="'@(_InnerPackageCacheFiles)' != ''" /> - + @@ -867,14 +860,10 @@ - - + DependsOnTargets="RepoTest;CleanupRepo" /> diff --git a/repo-projects/aspnetcore.proj b/repo-projects/aspnetcore.proj index 1088800e2fd..92aec5fbff7 100644 --- a/repo-projects/aspnetcore.proj +++ b/repo-projects/aspnetcore.proj @@ -36,10 +36,6 @@ true - - $(BuildArgs) $(FlagParameterPrefix)no-build-repo-tasks - - diff --git a/repo-projects/fsharp.proj b/repo-projects/fsharp.proj index 05824c08646..ed4792c458b 100644 --- a/repo-projects/fsharp.proj +++ b/repo-projects/fsharp.proj @@ -22,7 +22,7 @@ differently from the standard MSBuild arg set. Including both args is fine, but the custom sourcebuild arg is the one that's required. This avoids running bootstrapping twice. --> - $(BuildArgs) $(FlagParameterPrefix)sourceBuild $(FlagParameterPrefix)tfm $(NetCurrent) /p:SourceBuildBootstrapTfm=$(NetCurrent) + $(BuildArgs) $(FlagParameterPrefix)sourceBuild $(FlagParameterPrefix)tfm $(NetCurrent) diff --git a/repo-projects/roslyn.proj b/repo-projects/roslyn.proj index effcc998bc3..7af336799ae 100644 --- a/repo-projects/roslyn.proj +++ b/repo-projects/roslyn.proj @@ -11,6 +11,8 @@ $(BuildActions) $(FlagParameterPrefix)sign $(BuildArgs) /p:TreatWarningsAsErrors=false + + $(BuildArgs) /p:RestoreEnablePackagePruning=false diff --git a/repo-projects/runtime.proj b/repo-projects/runtime.proj index 65057174f78..004054f62b4 100644 --- a/repo-projects/runtime.proj +++ b/repo-projects/runtime.proj @@ -1,6 +1,9 @@ + + true + $(ProjectDirectory)build$(ShellExtension) @@ -12,37 +15,45 @@ true $(BuildArgs) $(FlagParameterPrefix)os $(TargetOS) - true - true + $(BuildArgs) $(FlagParameterPrefix)usemonoruntime - - $(BuildArgs) /p:DotNetBuildAllRuntimePacks=true + + true + $(BuildArgs) $(FlagParameterPrefix)cross - - $(BuildArgs) /p:WasmEnableThreads=true - $(BuildArgs) /p:MonoEnableLLVM=$(MonoEnableLLVM) - $(BuildArgs) /p:MonoAOTEnableLLVM=$(MonoAOTEnableLLVM) - $(BuildArgs) /p:MonoBundleLLVMOptimizer=$(MonoBundleLLVMOptimizer) - $(BuildArgs) $(FlagParameterPrefix)pgoinstrument + + $(BuildArgs) --outputrid $(TargetRid) - $(BuildArgs) /p:UseSystemLibs=$(UseSystemLibs) + + $(BuildArgs) --bootstrap + + + $(BuildArgs) /p:DotNetBuildAllRuntimePacks=true $(BuildArgs) /p:DotNetEsrpToolPath=$(DotNetEsrpToolPath) - - $(BuildArgs) /p:NetCoreAppToolCurrentVersion=10.0 - - - true + + $(BuildArgs) /p:WasmEnableThreads=$(WasmEnableThreads) + $(BuildArgs) /p:MonoEnableLLVM=$(MonoEnableLLVM) + $(BuildArgs) /p:MonoAOTEnableLLVM=$(MonoAOTEnableLLVM) + $(BuildArgs) /p:MonoBundleLLVMOptimizer=$(MonoBundleLLVMOptimizer) + $(BuildArgs) $(FlagParameterPrefix)pgoinstrument - - false + + +$(UseSystemLibs) + $(BuildArgs) --cmakeargs -DCLR_CMAKE_USE_SYSTEM_BROTLI=true + $(BuildArgs) --cmakeargs -DCLR_CMAKE_USE_SYSTEM_LIBUNWIND=true + + + $(BuildArgs) --cmakeargs -DCLR_CMAKE_USE_SYSTEM_RAPIDJSON=true + $(BuildArgs) --cmakeargs -DCLR_CMAKE_USE_SYSTEM_ZLIB=true + $(BuildArgs) /p:FeatureXplatEventSource=false diff --git a/repo-projects/source-build-externals.proj b/repo-projects/source-build-externals.proj index 023a6739cc8..b51baf83183 100644 --- a/repo-projects/source-build-externals.proj +++ b/repo-projects/source-build-externals.proj @@ -1,15 +1,5 @@ - - - true - - diff --git a/src/arcade/Documentation/UnifiedBuild/Unified-Build-Controls.md b/src/arcade/Documentation/UnifiedBuild/Unified-Build-Controls.md index 872e1416761..e003dfd0417 100644 --- a/src/arcade/Documentation/UnifiedBuild/Unified-Build-Controls.md +++ b/src/arcade/Documentation/UnifiedBuild/Unified-Build-Controls.md @@ -111,21 +111,14 @@ The following context controls will be implemented. These controls should be use | **Name** | **Values** | **Default** | **Description** | | -------- | -------- | -------- | -------- | -| DotNetBuild | "true", "false", "" | "" | This is a general identification control that essentially identifies whether the infrastructure is building in any kind of Unified Build mode. This serves as a way to conditionalize non-phase specific infrastructure in a general manner.
Generally, this is `DotNetBuildPhase != ‘’`
In general, uses of this switch should be limited to infrastructure, though it is possible that those infrastructure uses may affect the build output, especially in cases where a repo maintains a separate official build. | - -#### Exclusive Context Controls - -| **Name** | **Values** | **Default** | **Description** | -| -------- | -------- | -------- | -------- | -| DotNetBuildPhase | "Orchestrator", "Repo", "InnerRepo", "" | "" | Exclusive phase control identifying the phase currently executing.
Generally, this replaces uses of `ArcadeInnerBuildFromSource` (exclusive inner build) as well as common conditionals like `ArcadeBuildFromSource && !ArcadeInnerBuildFromSource`. | +| DotNetBuild | "true", "false", "" | "" | This is a general identification control that essentially identifies whether the infrastructure is building in any kind of Unified Build mode. This serves as a way to conditionalize non-phase specific infrastructure in a general manner.
In general, uses of this switch should be limited to infrastructure, though it is possible that those infrastructure uses may affect the build output, especially in cases where a repo maintains a separate official build. | #### Inclusive Context Controls | **Name** | **Values** | **Default** | **Description** | | -------- | -------- | -------- | -------- | -| DotNetBuildInnerRepo | "true", "false", "" | "" | When "true", indicates that the infrastructure is executing within the inner repo build. This is equivalent to `ArcadeInnerBuildFromSource``. | -| DotNetBuildOrchestrator | "true", "false", "" | "" | When "true", indicates that the infrastructure is executing within the orchestrator, outer repo build, and inner repo build.
This is roughly equivalent to `DotNetBuildFromSourceFlavor` as `Product`` in the current control set. | -| DotNetBuildRepo | "true", "false", "" | "" | When "true", indicates that the infrastructure is executing within outer repo build or inner repo build phases.
This is essentially the same as the legacy `ArcadeBuildFromSource`. | +| DotNetBuildOrchestrator | "true", "false", "" | "" | When "true", indicates that the infrastructure is executing within the orchestrator and repo build.
This is roughly equivalent to `DotNetBuildFromSourceFlavor` as `Product`` in the current control set. | +| DotNetBuildRepo | "true", "false", "" | "" | When "true", indicates that the infrastructure is executing within repo build. | ### Resource Controls diff --git a/src/arcade/eng/Version.Details.xml b/src/arcade/eng/Version.Details.xml index e1661c4d28e..3a4333e291f 100644 --- a/src/arcade/eng/Version.Details.xml +++ b/src/arcade/eng/Version.Details.xml @@ -1,6 +1,6 @@ - + @@ -27,21 +27,21 @@ https://github.com/dotnet/templating 43b5827697e501c442eb75ffff832cd4df2514fe - + https://github.com/dotnet/arcade - e46d1266547513110e67a3e4709fe8ecdfb20849 + fb40abf449b14a387edce364cee47052761cb2d1 - + https://github.com/dotnet/arcade - e46d1266547513110e67a3e4709fe8ecdfb20849 + fb40abf449b14a387edce364cee47052761cb2d1 - + https://github.com/dotnet/arcade-services - 24cbfec8065ff5e1fe870de8f62537a27eacd518 + 4cca82b3e6c89a153160f0ada17871cbdb82526f - + https://github.com/dotnet/arcade-services - 24cbfec8065ff5e1fe870de8f62537a27eacd518 + 4cca82b3e6c89a153160f0ada17871cbdb82526f https://github.com/dotnet/xharness diff --git a/src/arcade/eng/Versions.props b/src/arcade/eng/Versions.props index 83659d0dbf7..b6b3efc2d44 100644 --- a/src/arcade/eng/Versions.props +++ b/src/arcade/eng/Versions.props @@ -23,8 +23,8 @@ 9.0.0-beta.24223.1 - 1.1.0-beta.25229.6 - 1.1.0-beta.25229.6 + 1.1.0-beta.25252.1 + 1.1.0-beta.25252.1 2.0.0-beta5.25210.1 diff --git a/src/arcade/eng/common/core-templates/steps/source-build.yml b/src/arcade/eng/common/core-templates/steps/source-build.yml index 9292c9b67a3..325231215d5 100644 --- a/src/arcade/eng/common/core-templates/steps/source-build.yml +++ b/src/arcade/eng/common/core-templates/steps/source-build.yml @@ -19,19 +19,6 @@ steps: set -x df -h - # If file changes are detected, set CopyWipIntoInnerSourceBuildRepo to copy the WIP changes into the inner source build repo. - internalRestoreArgs= - if ! git diff --quiet; then - internalRestoreArgs='/p:CopyWipIntoInnerSourceBuildRepo=true' - # The 'Copy WIP' feature of source build uses git stash to apply changes from the original repo. - # This only works if there is a username/email configured, which won't be the case in most CI runs. - git config --get user.email - if [ $? -ne 0 ]; then - git config user.email dn-bot@microsoft.com - git config user.name dn-bot - fi - fi - # If building on the internal project, the internal storage variable may be available (usually only if needed) # In that case, add variables to allow the download of internal runtimes if the specified versions are not found # in the default public locations. @@ -71,7 +58,6 @@ steps: --restore --build --pack -bl \ ${{ parameters.platform.buildArguments }} \ $internalRuntimeDownloadArgs \ - $internalRestoreArgs \ $targetRidArgs \ $runtimeOsArgs \ $baseOsArgs \ @@ -80,26 +66,12 @@ steps: /p:DotNetBuildRepo=true \ displayName: Build -# Upload build logs for diagnosis. -- task: CopyFiles@2 - displayName: Prepare BuildLogs staging directory - inputs: - SourceFolder: '$(Build.SourcesDirectory)' - Contents: | - **/*.log - **/*.binlog - artifacts/sb/prebuilt-report/** - TargetFolder: '$(Build.StagingDirectory)/BuildLogs' - CleanTargetFolder: true - continueOnError: true - condition: succeededOrFailed() - - template: /eng/common/core-templates/steps/publish-pipeline-artifacts.yml parameters: is1ESPipeline: ${{ parameters.is1ESPipeline }} args: displayName: Publish BuildLogs - targetPath: '$(Build.StagingDirectory)/BuildLogs' + targetPath: artifacts/log/$[ coalesce(variables._BuildConfig, 'Release') ]/ artifactName: BuildLogs_SourceBuild_${{ parameters.platform.name }}_Attempt$(System.JobAttempt) continueOnError: true condition: succeededOrFailed() diff --git a/src/arcade/global.json b/src/arcade/global.json index 6662a179b57..b1105f6f98b 100644 --- a/src/arcade/global.json +++ b/src/arcade/global.json @@ -7,8 +7,8 @@ "dotnet": "10.0.100-preview.3.25201.16" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25229.4", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25229.4", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25252.4", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25252.4", "Microsoft.Build.NoTargets": "3.7.0" } } diff --git a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/AfterSolutionBuild.proj b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/AfterSolutionBuild.proj index 4a9cdd21249..54ede91854d 100644 --- a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/AfterSolutionBuild.proj +++ b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/AfterSolutionBuild.proj @@ -17,6 +17,7 @@ + diff --git a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/Build.proj b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/Build.proj index f41aac7ff30..1cd90849188 100644 --- a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/Build.proj +++ b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/Build.proj @@ -11,7 +11,6 @@ Configuration Build configuration: "Debug", "Release", etc. DotNetBuildRepo Build the repo as part of the entire .NET stack. - DotNetBuildInnerRepo Build the repo as part of the entire .NET stack. This switch is used on the inner repo invocation and should not be passed by the user. DotNetBuildOrchestrator Build the entire .NET stack. DotNetBuildPass While building the repo as part of the entire .NET stack, this parameter specifies which build pass the current build is part of. DotNetBuildSourceOnly Build the repo as part of the entire .NET stack with no external dependencies. @@ -53,8 +52,6 @@ - - @@ -79,7 +76,7 @@ Don't do this filtering in non-unified builds to allow repos to define how different build passes are handled in their own repo-specific builds. --> - + <_ProjectToBuildCurrentBuildPass Include="@(ProjectToBuild->WithMetadataValue('DotNetBuildPass', '$(_DotNetBuildPassNormalized)'))" /> @@ -264,7 +261,7 @@ + Condition="'@(_SolutionBuildTargets)' != ''" /> - - - - - - - <_ShouldRunPublish Condition="'$(DotNetBuildPhase)' == 'InnerRepo' and '$(DotNetBuildOrchestrator)' == 'true'">true - <_ShouldRunPublish Condition="'$(DotNetBuildPhase)' != 'InnerRepo' and '$(DotNetBuildOrchestrator)' != 'true'">true - <_ShouldRunPublish Condition="'$(UseArPowBuildInfra)' == 'false'">true - + Condition="'@(_SolutionBuildTargets)' != ''" /> <_PublishProps Include="@(_CommonProps)"/> @@ -318,7 +286,7 @@ + Condition="'$(Publish)' == 'true'"/> - - - + $(NuGetPackageRoot)microsoft.dotnet.sourcebuild.tasks\$(MicrosoftDotNetSourceBuildTasksVersion)\build\ - - + + + $(RepoRoot) + $(NuGetPackageRoot) + $(ArtifactsLogDir) + $(PrebuiltUsageReportDir)prebuilt-usage.xml + + - - - - + + + + - - - - + + - - $([MSBuild]::NormalizePath('$(SourceBuildPrebuiltReportDir)prebuilt-usage.xml')) - - @@ -42,9 +40,7 @@ + OutputDirectory="$(PrebuiltUsageReportDir)" /> - - diff --git a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/Publish.proj b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/Publish.proj index 1b544558109..142907fdb90 100644 --- a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/Publish.proj +++ b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/Publish.proj @@ -37,11 +37,10 @@ - + true @@ -52,7 +51,7 @@ so we want to inclue them here so they can be in the vertical's final manifest. The VMR tooling to produce the final merged manifest for the VMR build as a whole will filter them out. --> - + @@ -72,11 +71,7 @@ false true - - true + true false false diff --git a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/RepoDefaults.props b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/RepoDefaults.props index 302d856b3af..75b312d7f5c 100644 --- a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/RepoDefaults.props +++ b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/RepoDefaults.props @@ -11,15 +11,11 @@ $(Platform) - - - true - - - InnerRepo - Repo - Orchestrator + + true + + true diff --git a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/RepoLayout.props b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/RepoLayout.props index e4a6e578d4f..d0927a742da 100644 --- a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/RepoLayout.props +++ b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/RepoLayout.props @@ -5,14 +5,6 @@ Properties describing the layout of the repo. --> - - - $([MSBuild]::NormalizeDirectory('$(NuGetPackageRoot)')) - $([MSBuild]::NormalizeDirectory('$(NUGET_PACKAGES)')) - $([MSBuild]::NormalizeDirectory('$(UserProfile)', '.nuget', 'packages')) - $([MSBuild]::NormalizeDirectory('$(HOME)', '.nuget', 'packages')) - - $([MSBuild]::NormalizeDirectory('$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), 'global.json'))')) @@ -58,4 +50,17 @@ $([MSBuild]::NormalizeDirectory('$(VisualStudioSetupOutputPath)', 'DevDivPackages'))
+ + + $([MSBuild]::NormalizeDirectory('$(NuGetPackageRoot)')) + $([MSBuild]::NormalizeDirectory('$(NUGET_PACKAGES)')) + + + $([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', '.prebuilt-packages')) + + + $([MSBuild]::NormalizeDirectory('$(UserProfile)', '.nuget', 'packages')) + $([MSBuild]::NormalizeDirectory('$(HOME)', '.nuget', 'packages')) + + diff --git a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/SourceBuild/Noop.proj b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/SourceBuild/Noop.proj deleted file mode 100644 index c4a35662a15..00000000000 --- a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/SourceBuild/Noop.proj +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - diff --git a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/SourceBuild/README.md b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/SourceBuild/README.md deleted file mode 100644 index 1b8394f9f74..00000000000 --- a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/SourceBuild/README.md +++ /dev/null @@ -1,47 +0,0 @@ -# Running source only builds - -These args control parts of source only build: - -* `-sb` - Enable simple developer machine repro defaults. -* Not implemented but recognized as potentially useful: - * Disable Git repo isolation (slightly faster, but not recommended for dev machines). We may want to use this for CI. - * Clone and build upstreams from source rather than using intermediate nupkgs. - * Not as useful as it sounds: this is only the "production" build so building this way is still not appropriate for a typical Linux distro archive. - -*All* vmr-build functionality is brought in only when `DotNetBuild` -is set to true, to ensure the new MSBuild props/targets don't introduce bugs -into ordinary builds. - -File issues encountered with this directory's tooling in the -[dotnet/source-build](https://github.com/dotnet/source-build) repository rather -than [dotnet/arcade](https://github.com/dotnet/arcade) to contact the team -maintaining this functionality directly. - -## MSBuild execution - -The source-build targets work by having the build noop, and instead recursively -call an inner build after some setup. The targets work roughly like this: - -* Run `./build.sh -sb` - * Run `dotnet msbuild ... Build.proj /p:DotNetBuildRepo=true` - * [Hook] Before **Outer Execute**: - * Clone the source into `artifacts/sb/src` - * Assemble a build command by appending to the `dotnet msbuild` call. - * Run `dotnet msbuild ... Build.proj /p:DotNetBuildRepo=true ... /p:DotNetBuildInnerRepo=true` - * [Hook] Before **Inner Execute**: - * Compile source-build MSBuild tasks. (Temporary, should migrate to Arcade task DLL.) - * During **Inner Execute**: - * `MSBuild Projects=Tools.proj Targets=Restore` - * [Hook] Inject intermediate nupkg package reference through MSBuild task. - * [Hook] After Restore, copy the extracted source-built nupkgs to a new dir and inject the dir into the NuGet.config. - * The build happens! - * **Inner Execute** complete! - * Create intermediate nupkg that contains the inner source-build's artifacts. - * MSBuild `Projects=SourceBuildIntermediate.proj Targets=Restore;Pack` - * Empty out the list of `ProjectToBuild`, because we already built them from source. - * Put `Noop.proj` in the list as a sentinel value. - * During **Outer Execute**: - * MSBuild `Projects=Tools.proj Targets=Restore` - * Does nothing interesting. - * "Builds" `Noop.proj`, doing nothing. - * **Outer Execute** complete! diff --git a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/SourceBuild/SourceBuildArcade.targets b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/SourceBuild/SourceBuildArcade.targets deleted file mode 100644 index 41ddd5500f3..00000000000 --- a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/SourceBuild/SourceBuildArcade.targets +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - .zip - - - 0 - - - - .tar.gz - -- - false - - - - - - - - true - - - $([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'sb')) - $([MSBuild]::NormalizeDirectory('$(SourceBuildOutputDir)', 'src')) - $(RepoRoot) - $([MSBuild]::NormalizeDirectory('$(SourceBuildOutputDir)', 'package-cache')) - - $([MSBuild]::NormalizeDirectory('$(SourceBuildOutputDir)', 'prebuilt-report')) - - - $([MSBuild]::NormalizeDirectory('$(CurrentRepoSourceBuildSourceDir)', 'artifacts')) - $([MSBuild]::NormalizeDirectory('$(CurrentRepoSourceBuildArtifactsDir)', 'log', '$(Configuration)')) - - - diff --git a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/SourceBuild/SourceBuildArcadeBuild.targets b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/SourceBuild/SourceBuildArcadeBuild.targets deleted file mode 100644 index c3ba4a616bf..00000000000 --- a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/SourceBuild/SourceBuildArcadeBuild.targets +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - - - $([MSBuild]::NormalizePath('$(CurrentRepoSourceBuildArtifactsLogsDir)', 'source-inner-build.binlog')) - - $(CurrentRepoSourceBuildSourceDir) - $(RepoRoot) - - true - - <_DirSeparatorEscapedCharForExecArg Condition="'$(OS)' == 'Windows_NT'">\ - <_DirSeparatorEscapedCharForExecArg Condition="'$(OS)' != 'Windows_NT'" /> - - - - - - - - - - - - - - - $(InnerBuildArgs) /p:DotNetBuildInnerRepo=true - $(InnerBuildArgs) /p:DotNetBuildSourceOnly=$(DotNetBuildSourceOnly) - $(InnerBuildArgs) /p:DotNetBuildTargetRidOnly=$(DotNetBuildTargetRidOnly) - - $(InnerBuildArgs) /p:RepoRoot="$(InnerSourceBuildRepoRoot)$(_DirSeparatorEscapedCharForExecArg)" - - $(InnerBuildArgs) /p:ArtifactsDir="$(CurrentRepoSourceBuildArtifactsDir)$(_DirSeparatorEscapedCharForExecArg)" - - $(InnerBuildArgs) /bl:"$(CurrentRepoSourceBuildBinlogFile)" - - $(InnerBuildArgs) /p:ContinuousIntegrationBuild=true - - - $(InnerBuildArgs) /p:SourceBuildOutputDir="$(SourceBuildOutputDir)$(_DirSeparatorEscapedCharForExecArg)" - - $(InnerBuildArgs) /p:DotNetPackageVersionPropsPath="$(DotNetPackageVersionPropsPath)" - - $(InnerBuildArgs) /p:GitHubRepositoryName=$(GitHubRepositoryName) - - - - - - - - - - - - - - - - - - - - - - - - true - - - $(ARCADE_BUILD_TOOL_COMMAND) - - - - - - - - - - - - - diff --git a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/TargetFrameworkFilters.BeforeCommonTargets.targets b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/TargetFrameworkFilters.BeforeCommonTargets.targets index c9a309894e1..d78e613edd0 100644 --- a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/TargetFrameworkFilters.BeforeCommonTargets.targets +++ b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/TargetFrameworkFilters.BeforeCommonTargets.targets @@ -4,7 +4,7 @@ - netstandard2.0%3bnetstandard2.1%3bnetcoreapp2.1%3bnetcoreapp3.1%3bnet5.0%3bnet6.0%3bnet7.0%3bnet8.0%3bnet9.0%3bnet10.0 + netstandard2.0%3bnetstandard2.1%3bnetcoreapp2.1%3bnetcoreapp3.1%3bnet5.0%3bnet6.0%3bnet7.0%3bnet8.0%3bnet9.0%3bnet10.0 <_EnableTargetFrameworkFiltering>false <_EnableTargetFrameworkFiltering Condition="'$(NoTargetFrameworkFiltering)' != 'true' and '$(DotNetTargetFrameworkFilter)' != ''">true diff --git a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/Tools.proj b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/Tools.proj index 78245829711..98169efb405 100644 --- a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/Tools.proj +++ b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/Tools.proj @@ -37,14 +37,9 @@
- - <_ImportOrUseTooling>false - <_ImportOrUseTooling Condition="'$(DotNetBuildSourceOnly)' != 'true' or ('$(DotNetBuildPhase)' == 'Repo' and '$(DotNetBuildOrchestrator)' != 'true')">true + <_ImportOrUseTooling Condition="'$(DotNetBuildSourceOnly)' != 'true' or ('$(DotNetBuildRepo)' == 'true' and '$(DotNetBuildOrchestrator)' != 'true')">true @@ -101,7 +96,7 @@ + Condition="'$(PrebuiltUsage)' == 'true'" /> diff --git a/src/arcade/src/Microsoft.DotNet.Build.Tasks.Packaging/src/NuGetUtility.cs b/src/arcade/src/Microsoft.DotNet.Build.Tasks.Packaging/src/NuGetUtility.cs index 1233dc63852..323a7d283d7 100644 --- a/src/arcade/src/Microsoft.DotNet.Build.Tasks.Packaging/src/NuGetUtility.cs +++ b/src/arcade/src/Microsoft.DotNet.Build.Tasks.Packaging/src/NuGetUtility.cs @@ -37,7 +37,9 @@ internal static IEnumerable GetAllVersionsForPackageId(string packageId { var sourceRepository = new SourceRepository(packageSource, Repository.Provider.GetCoreV3()); var packageMetadataResource = sourceRepository.GetResourceAsync().GetAwaiter().GetResult(); +#pragma warning disable CA2025 // we force GetMetadataAsync to be synchronous so sourceCacheContext can't be disposed early searchMetadata = packageMetadataResource.GetMetadataAsync(packageId, includePrerelease, includeUnlisted, sourceCacheContext, logger, cancellationToken).GetAwaiter().GetResult(); +#pragma warning restore loadedData = true; } catch (Exception e) diff --git a/src/arcade/src/Microsoft.DotNet.SignTool.Tests/SignToolTests.cs b/src/arcade/src/Microsoft.DotNet.SignTool.Tests/SignToolTests.cs index 0ff4fa09b2f..971edb06198 100644 --- a/src/arcade/src/Microsoft.DotNet.SignTool.Tests/SignToolTests.cs +++ b/src/arcade/src/Microsoft.DotNet.SignTool.Tests/SignToolTests.cs @@ -259,6 +259,8 @@ public static IEnumerable GetSignableExtensions() } } + public static bool PlatformSupportsStrongNameAlgorithm { get; } = StrongNameSupportHelper.GetPlatformSupportsRSASHA1(); + public SignToolTests(ITestOutputHelper output) { _tmpDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); @@ -703,7 +705,7 @@ public void SkipStrongNamingForCrossGennedBinary() }); } - [Fact] + [ConditionalFact(nameof(PlatformSupportsStrongNameAlgorithm))] public void SkipStrongNamingBinaryButDontSkipAuthenticode() { // List of files to be considered for signing @@ -3076,7 +3078,7 @@ private void WriteBytesToLocation(Stream inputStream, Stream outputStream, int o /// /// Verify that flipbit works properly by flipping twice. /// - [Fact] + [ConditionalFact(nameof(PlatformSupportsStrongNameAlgorithm))] public void NoFlipButWriteShouldVerify() { // We're going to open the file and flip a bit in the checksum @@ -3106,7 +3108,7 @@ public void IncorrectChecksumsDoNotValidate() // This binary has had a resource added after it was strong name. This invalidated the checksum too, // so we write the expected checksum. - [Fact] + [ConditionalFact(nameof(PlatformSupportsStrongNameAlgorithm))] public void InvalidatedSNSignatureDoesNotValidate() { using var inputStream = File.OpenRead(GetResourcePath("InvalidatedStrongName.dll")); @@ -3122,7 +3124,7 @@ public void InvalidatedSNSignatureDoesNotValidate() StrongNameHelper.IsSigned(outputStream).Should().BeFalse(); } - [Fact] + [ConditionalFact(nameof(PlatformSupportsStrongNameAlgorithm))] public void ValidStrongNameSignaturesValidate() { StrongNameHelper.IsSigned(GetResourcePath("SignedLibrary.dll")).Should().BeTrue(); @@ -3136,7 +3138,7 @@ public void ValidStrongNameSignaturesValidateWithFallback() StrongNameHelper.IsSigned_Legacy(GetResourcePath("StrongNamedWithEcmaKey.dll"), s_snPath).Should().BeTrue(); } - [Theory] + [ConditionalTheory(nameof(PlatformSupportsStrongNameAlgorithm))] [InlineData("OpenSigned.dll", "OpenSignedCorrespondingKey.snk", true)] [InlineData("DelaySignedWithOpen.dll", "OpenSignedCorrespondingKey.snk", false)] public void SigningSignsAsExpected(string file, string key, bool initiallySigned) diff --git a/src/arcade/src/Microsoft.DotNet.SignTool.Tests/StrongNameSupportHelper.cs b/src/arcade/src/Microsoft.DotNet.SignTool.Tests/StrongNameSupportHelper.cs new file mode 100644 index 00000000000..515dd27b1ab --- /dev/null +++ b/src/arcade/src/Microsoft.DotNet.SignTool.Tests/StrongNameSupportHelper.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Security.Cryptography; + +namespace Microsoft.DotNet.SignTool.Tests +{ + internal static class StrongNameSupportHelper + { + internal static bool GetPlatformSupportsRSASHA1() + { + using (RSA rsa = RSA.Create(2048)) + { + try + { + rsa.SignData(Array.Empty(), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); + return true; + } + catch (CryptographicException) + { + return false; + } + } + } + } +} diff --git a/src/arcade/tests/UnitTests.proj b/src/arcade/tests/UnitTests.proj index 3d156670cc2..a497dadcc2d 100644 --- a/src/arcade/tests/UnitTests.proj +++ b/src/arcade/tests/UnitTests.proj @@ -59,9 +59,9 @@
- + - + @@ -71,9 +71,9 @@ - + - + diff --git a/src/aspnetcore/.github/policies/resourceManagement.yml b/src/aspnetcore/.github/policies/resourceManagement.yml index 0b6766c8a45..1d002ad979d 100644 --- a/src/aspnetcore/.github/policies/resourceManagement.yml +++ b/src/aspnetcore/.github/policies/resourceManagement.yml @@ -663,7 +663,7 @@ configuration: - isAction: action: Opened - isActivitySender: - user: app/dependabot + user: dependabot[bot] issueAuthor: False - targetsBranch: branch: main diff --git a/src/aspnetcore/eng/DotNetBuild.props b/src/aspnetcore/eng/DotNetBuild.props deleted file mode 100644 index 50e2eb96238..00000000000 --- a/src/aspnetcore/eng/DotNetBuild.props +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - aspnetcore - true - - - - - - - - - - - - - <_AdditionalRepoTaskBuildArgs /> - <_AdditionalRepoTaskBuildArgs Condition="'$(DotNetRuntimeSourceFeed)' != ''" >$(_AdditionalRepoTaskBuildArgs) --runtimesourcefeed $(DotNetRuntimeSourceFeed) - <_AdditionalRepoTaskBuildArgs Condition="'$(DotNetRuntimeSourceFeedKey)' != ''" >$(_AdditionalRepoTaskBuildArgs) --runtimesourcefeedkey $(DotNetRuntimeSourceFeedKey) - <_AdditionalRepoTaskBuildArgs Condition="'$(RestoreConfigFile)' != ''" >$(_AdditionalRepoTaskBuildArgs) /p:RestoreConfigFile=$(RestoreConfigFile) - - - - - - - - - - - - - - - - $(CurrentRepoSourceBuildArtifactsDir)\installers\$(Configuration)\ - - - - - - - - - - - diff --git a/src/aspnetcore/eng/Version.Details.xml b/src/aspnetcore/eng/Version.Details.xml index f9507ed0fa3..30507643f3a 100644 --- a/src/aspnetcore/eng/Version.Details.xml +++ b/src/aspnetcore/eng/Version.Details.xml @@ -8,336 +8,337 @@ See https://github.com/dotnet/arcade/blob/master/Documentation/Darc.md for instructions on using darc. --> - + - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 + - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 @@ -356,44 +357,44 @@ https://github.com/dotnet/roslyn afdd413cee50c16318620252e4e64dc326e2d300 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 https://github.com/dotnet/extensions diff --git a/src/aspnetcore/eng/Versions.props b/src/aspnetcore/eng/Versions.props index d9c03e13a57..cf8d7a0571b 100644 --- a/src/aspnetcore/eng/Versions.props +++ b/src/aspnetcore/eng/Versions.props @@ -67,94 +67,94 @@ --> - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 9.5.0-preview.1.25223.1 9.5.0-preview.1.25223.1 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 4.13.0-3.24613.7 @@ -167,12 +167,12 @@ 6.2.4 6.2.4 - 10.0.0-beta.25228.104 - 10.0.0-beta.25228.104 - 10.0.0-beta.25228.104 - 10.0.0-beta.25228.104 + 10.0.0-beta.25251.105 + 10.0.0-beta.25251.105 + 10.0.0-beta.25251.105 + 10.0.0-beta.25251.105 - 10.0.0-preview.25228.104 + 10.0.0-preview.25251.105 1.0.0-prerelease.25217.3 1.0.0-prerelease.25217.3 @@ -226,13 +226,12 @@ 6.0.0 6.0.0 - 17.4.0 1.2.0 - 17.4.0 - 17.4.0 - 17.4.0 1.2.6 - 17.4.0 + 17.8.3 + 17.8.3 + 17.8.3 + 17.8.3 - false - true - - - ..\..\..\System.CommandLine\bin\Release\$(TargetFrameworkForNETSDK)\System.CommandLine.dll - + + Exe + $(TargetFrameworkForNETSDK) + + false + true + Guard + - - - $(SystemCommandLineDllPath) - - + + ..\..\..\System.CommandLine\bin\Release\$(TargetFrameworkForNETSDK)\System.CommandLine.dll + + + + + $(SystemCommandLineDllPath) + + diff --git a/src/deployment-tools/eng/Version.Details.xml b/src/deployment-tools/eng/Version.Details.xml index fa7e8568896..109df77e736 100644 --- a/src/deployment-tools/eng/Version.Details.xml +++ b/src/deployment-tools/eng/Version.Details.xml @@ -1,11 +1,11 @@ - + - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 diff --git a/src/deployment-tools/global.json b/src/deployment-tools/global.json index 4ae23dd54d1..8c03fac5073 100644 --- a/src/deployment-tools/global.json +++ b/src/deployment-tools/global.json @@ -8,7 +8,7 @@ "dotnet": "10.0.100-preview.3.25201.16" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25251.102", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25251.105", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0" } diff --git a/src/diagnostics/eng/Version.Details.xml b/src/diagnostics/eng/Version.Details.xml index 0b105f2cac4..4cef3f20b56 100644 --- a/src/diagnostics/eng/Version.Details.xml +++ b/src/diagnostics/eng/Version.Details.xml @@ -1,5 +1,5 @@ - + https://github.com/microsoft/clrmd @@ -11,37 +11,37 @@ - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 78c5fa9a48d469a19ab5a61c16c955c1f370b5be - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 78c5fa9a48d469a19ab5a61c16c955c1f370b5be https://github.com/dotnet/arcade ccfe6da198c5f05534863bbb1bff66e830e0c6ab - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 78c5fa9a48d469a19ab5a61c16c955c1f370b5be - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 78c5fa9a48d469a19ab5a61c16c955c1f370b5be - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 78c5fa9a48d469a19ab5a61c16c955c1f370b5be - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 78c5fa9a48d469a19ab5a61c16c955c1f370b5be - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 78c5fa9a48d469a19ab5a61c16c955c1f370b5be https://github.com/dotnet/roslyn diff --git a/src/diagnostics/eng/Versions.props b/src/diagnostics/eng/Versions.props index 5a0b1f21636..ca58f62b22f 100644 --- a/src/diagnostics/eng/Versions.props +++ b/src/diagnostics/eng/Versions.props @@ -16,13 +16,13 @@ - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 + 10.0.0-preview.5.25229.109 + 10.0.0-preview.5.25229.109 - 10.0.0-preview.5.25228.104 - 10.0.0-preview.5.25228.104 + 10.0.0-preview.5.25229.109 + 10.0.0-preview.5.25229.109 - 10.0.100-preview.5.25228.104 + 10.0.100-preview.5.25229.109 @@ -39,7 +39,7 @@ 6.0.0 4.0.0-beta.25228.1 17.10.0-beta1.24272.1 - 3.1.16 + 3.1.21 6.0.0 6.0.4 6.0.0 @@ -55,7 +55,7 @@ 8.0.0 8.0.5 2.0.3 - 10.0.0-beta.25228.104 + 10.0.0-beta.25229.109 1.2.0-beta.556 7.0.0-beta.22316.2 10.0.26100.1 diff --git a/src/diagnostics/global.json b/src/diagnostics/global.json index 8d065d271d3..7665087403f 100644 --- a/src/diagnostics/global.json +++ b/src/diagnostics/global.json @@ -17,6 +17,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "3.5.0", - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25228.104" + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25229.109" } } diff --git a/src/diagnostics/src/Tools/dotnet-gcdump/DotNetHeapDump/GCHeapDump.cs b/src/diagnostics/src/Tools/dotnet-gcdump/DotNetHeapDump/GCHeapDump.cs index 39ac9ad33ea..bd5afb7dc21 100644 --- a/src/diagnostics/src/Tools/dotnet-gcdump/DotNetHeapDump/GCHeapDump.cs +++ b/src/diagnostics/src/Tools/dotnet-gcdump/DotNetHeapDump/GCHeapDump.cs @@ -13,17 +13,17 @@ using Address = System.UInt64; /// -/// Represents a .GCDump file. You can open it for reading with the construtor +/// Represents a .GCDump file. You can open it for reading with the constructor /// and you can write one with WriteMemoryGraph /// public class GCHeapDump : IFastSerializable, IFastSerializableVersion { public GCHeapDump(string inputFileName) : - this(new Deserializer(inputFileName, new SerializationConfiguration() { StreamLabelWidth = StreamLabelWidth.FourBytes })) + this(new Deserializer(inputFileName, SerializationSettings.Default.WithStreamLabelWidth(StreamLabelWidth.FourBytes))) { } public GCHeapDump(Stream inputStream, string streamName) : - this(new Deserializer(inputStream, streamName, new SerializationConfiguration() { StreamLabelWidth = StreamLabelWidth.FourBytes })) + this(new Deserializer(inputStream, streamName, SerializationSettings.Default.WithStreamLabelWidth(StreamLabelWidth.FourBytes))) { } /// @@ -193,7 +193,7 @@ public static Dictionary GetProcessesWithGCHeaps() private void Write(string outputFileName) { Debug.Assert(MemoryGraph != null); - Serializer serializer = new(new IOStreamStreamWriter(outputFileName, config: new SerializationConfiguration() { StreamLabelWidth = StreamLabelWidth.FourBytes }), this); + Serializer serializer = new(new IOStreamStreamWriter(outputFileName, settings: SerializationSettings.Default.WithStreamLabelWidth(StreamLabelWidth.FourBytes)), this); serializer.Close(); } diff --git a/src/diagnostics/src/Tools/dotnet-gcdump/DotNetHeapDump/Graph.cs b/src/diagnostics/src/Tools/dotnet-gcdump/DotNetHeapDump/Graph.cs index dc6760fb46d..c5d5520ac5d 100644 --- a/src/diagnostics/src/Tools/dotnet-gcdump/DotNetHeapDump/Graph.cs +++ b/src/diagnostics/src/Tools/dotnet-gcdump/DotNetHeapDump/Graph.cs @@ -469,7 +469,7 @@ private void ClearWorker() { RootIndex = NodeIndex.Invalid; m_writer ??= new SegmentedMemoryStreamWriter(m_expectedNodeCount * 8, - m_isVeryLargeGraph ? new SerializationConfiguration() { StreamLabelWidth = StreamLabelWidth.EightBytes } : null); + m_isVeryLargeGraph ? SerializationSettings.Default.WithStreamLabelWidth(StreamLabelWidth.EightBytes) : SerializationSettings.Default); m_totalSize = 0; m_totalRefs = 0; @@ -597,7 +597,7 @@ public void FromStream(Deserializer deserializer) // TODO be lazy about reading in the blobs. int blobCount = deserializer.ReadInt(); SegmentedMemoryStreamWriter writer = new(blobCount, - m_isVeryLargeGraph ? new SerializationConfiguration() { StreamLabelWidth = StreamLabelWidth.EightBytes } : null); + m_isVeryLargeGraph ? SerializationSettings.Default.WithStreamLabelWidth(StreamLabelWidth.EightBytes) : SerializationSettings.Default); while (8 <= blobCount) { diff --git a/src/diagnostics/src/Tools/dotnet-gcdump/DotNetHeapDump/MemoryGraph.cs b/src/diagnostics/src/Tools/dotnet-gcdump/DotNetHeapDump/MemoryGraph.cs index 68696ccb629..4d803817632 100644 --- a/src/diagnostics/src/Tools/dotnet-gcdump/DotNetHeapDump/MemoryGraph.cs +++ b/src/diagnostics/src/Tools/dotnet-gcdump/DotNetHeapDump/MemoryGraph.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Collections.Generic; using System.Diagnostics; using FastSerialization; @@ -36,8 +37,7 @@ public void WriteAsBinaryFile(string outputFileName) } public static MemoryGraph ReadFromBinaryFile(string inputFileName) { - Deserializer deserializer = new(inputFileName); - deserializer.TypeResolver = typeName => System.Type.GetType(typeName); // resolve types in this assembly (and mscorlib) + Deserializer deserializer = new(inputFileName, SerializationSettings.Default); deserializer.RegisterFactory(typeof(MemoryGraph), delegate { return new MemoryGraph(1); }); deserializer.RegisterFactory(typeof(Module), delegate { return new Module(0); }); return (MemoryGraph)deserializer.GetEntryObject(); diff --git a/src/efcore/eng/Version.Details.xml b/src/efcore/eng/Version.Details.xml index e65d9e17619..2f3763be94a 100644 --- a/src/efcore/eng/Version.Details.xml +++ b/src/efcore/eng/Version.Details.xml @@ -1,84 +1,84 @@ - + - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 diff --git a/src/efcore/eng/Versions.props b/src/efcore/eng/Versions.props index 3fdb61b5ed5..8bcd1229fbd 100644 --- a/src/efcore/eng/Versions.props +++ b/src/efcore/eng/Versions.props @@ -16,24 +16,24 @@ False - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 - 10.0.0-beta.25251.102 + 10.0.0-beta.25251.105 17.13.9 diff --git a/src/efcore/global.json b/src/efcore/global.json index 7497505d190..98aa180e32b 100644 --- a/src/efcore/global.json +++ b/src/efcore/global.json @@ -13,7 +13,7 @@ } }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25251.102", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25251.102" + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25251.105", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25251.105" } } diff --git a/src/efcore/src/EFCore/ValueGeneration/SequentialGuidValueGenerator.cs b/src/efcore/src/EFCore/ValueGeneration/SequentialGuidValueGenerator.cs index 569de845e67..99c87700780 100644 --- a/src/efcore/src/EFCore/ValueGeneration/SequentialGuidValueGenerator.cs +++ b/src/efcore/src/EFCore/ValueGeneration/SequentialGuidValueGenerator.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers.Binary; using System.Runtime.InteropServices; namespace Microsoft.EntityFrameworkCore.ValueGeneration; @@ -35,17 +36,29 @@ public class SequentialGuidValueGenerator : ValueGenerator /// The value to be assigned to a property. public override Guid Next(EntityEntry entry) { - Span guidBytes = stackalloc byte[16]; - var succeeded = Guid.NewGuid().TryWriteBytes(guidBytes); - Check.DebugAssert(succeeded, "Could not write Guid to Span"); - var incrementedCounter = Interlocked.Increment(ref _counter); - Span counterBytes = stackalloc byte[sizeof(long)]; - MemoryMarshal.Write(counterBytes, in incrementedCounter); + var guid = Guid.NewGuid(); - if (!BitConverter.IsLittleEndian) - { - counterBytes.Reverse(); - } + var counter = BitConverter.IsLittleEndian + ? Interlocked.Increment(ref _counter) + : BinaryPrimitives.ReverseEndianness(Interlocked.Increment(ref _counter)); + + var counterBytes = MemoryMarshal.AsBytes( + new ReadOnlySpan(in counter)); + + // Guid uses a sequential layout where the first 8 bytes (_a, _b, _c) + // are subject to byte-swapping on big-endian systems when reading from + // or writing to a byte array (e.g., via MemoryMarshal or Guid constructors). + // The remaining 8 bytes (_d through _k) are interpreted as-is, + // regardless of endianness. + // + // Since we only modify the last 8 bytes of the Guid (bytes 8–15), + // byte order does not affect the result. + // + // This allows us to safely use MemoryMarshal.AsBytes to directly access + // and modify the Guid's underlying bytes without any extra conversions, + // which also slightly improves performance on big-endian architectures. + var guidBytes = MemoryMarshal.AsBytes( + new Span(ref guid)); guidBytes[08] = counterBytes[1]; guidBytes[09] = counterBytes[0]; @@ -56,7 +69,7 @@ public override Guid Next(EntityEntry entry) guidBytes[14] = counterBytes[3]; guidBytes[15] = counterBytes[2]; - return new Guid(guidBytes); + return guid; } /// diff --git a/src/emsdk/eng/Version.Details.xml b/src/emsdk/eng/Version.Details.xml index 18a6dabc016..23821fda6b1 100644 --- a/src/emsdk/eng/Version.Details.xml +++ b/src/emsdk/eng/Version.Details.xml @@ -1,54 +1,54 @@ - + - + https://github.com/dotnet/binaryen - 3d70e5233ae6b4fdbe94a891fadf0f3c860836db + 80ce9378dc799e9513e7faaa372aba9904d3958e - + https://github.com/dotnet/binaryen - 3d70e5233ae6b4fdbe94a891fadf0f3c860836db + 80ce9378dc799e9513e7faaa372aba9904d3958e - + https://github.com/dotnet/binaryen - 3d70e5233ae6b4fdbe94a891fadf0f3c860836db + 80ce9378dc799e9513e7faaa372aba9904d3958e - + https://github.com/dotnet/binaryen - 3d70e5233ae6b4fdbe94a891fadf0f3c860836db + 80ce9378dc799e9513e7faaa372aba9904d3958e - + https://github.com/dotnet/binaryen - 3d70e5233ae6b4fdbe94a891fadf0f3c860836db + 80ce9378dc799e9513e7faaa372aba9904d3958e - + https://github.com/dotnet/binaryen - 3d70e5233ae6b4fdbe94a891fadf0f3c860836db + 80ce9378dc799e9513e7faaa372aba9904d3958e - + https://github.com/dotnet/binaryen - 3d70e5233ae6b4fdbe94a891fadf0f3c860836db + 80ce9378dc799e9513e7faaa372aba9904d3958e - + https://github.com/dotnet/binaryen - 3d70e5233ae6b4fdbe94a891fadf0f3c860836db + 80ce9378dc799e9513e7faaa372aba9904d3958e - + https://github.com/dotnet/cpython - 683ba59cf4c8004f8b612ec989f71635ec7ac8bf + d2b3a4f371dc20282352d4248d4e2fe815137357 - + https://github.com/dotnet/cpython - 683ba59cf4c8004f8b612ec989f71635ec7ac8bf + d2b3a4f371dc20282352d4248d4e2fe815137357 - + https://github.com/dotnet/cpython - 683ba59cf4c8004f8b612ec989f71635ec7ac8bf + d2b3a4f371dc20282352d4248d4e2fe815137357 - + https://github.com/dotnet/cpython - 683ba59cf4c8004f8b612ec989f71635ec7ac8bf + d2b3a4f371dc20282352d4248d4e2fe815137357 https://github.com/dotnet/node @@ -82,69 +82,69 @@ https://github.com/dotnet/node 9be2b6333d1bd762e567741f0e37c78ad2740110 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 https://github.com/dotnet/emscripten @@ -152,117 +152,117 @@ - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/llvm-project - d38f1dd01fff4127bb86afa86c1e5ac44154a1d7 + 06dc649fc031114f675b184dc579d7c02d3d1f40 - + https://github.com/dotnet/dotnet - 721dc7a2a59416b21fc49447d264009d708d6000 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 721dc7a2a59416b21fc49447d264009d708d6000 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 721dc7a2a59416b21fc49447d264009d708d6000 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 721dc7a2a59416b21fc49447d264009d708d6000 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 721dc7a2a59416b21fc49447d264009d708d6000 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 721dc7a2a59416b21fc49447d264009d708d6000 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 721dc7a2a59416b21fc49447d264009d708d6000 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 diff --git a/src/emsdk/eng/Versions.props b/src/emsdk/eng/Versions.props index 200604774fd..a6fd9865c5b 100644 --- a/src/emsdk/eng/Versions.props +++ b/src/emsdk/eng/Versions.props @@ -18,19 +18,19 @@ 7.0.20 6.0.36 - 10.0.0-alpha.1.25220.1 - 10.0.0-alpha.1.25220.1 - 10.0.0-alpha.1.25220.1 - 10.0.0-alpha.1.25220.1 - 10.0.0-alpha.1.25220.1 - 10.0.0-alpha.1.25220.1 - 10.0.0-alpha.1.25220.1 - 10.0.0-alpha.1.25220.1 + 10.0.0-alpha.1.25227.1 + 10.0.0-alpha.1.25227.1 + 10.0.0-alpha.1.25227.1 + 10.0.0-alpha.1.25227.1 + 10.0.0-alpha.1.25227.1 + 10.0.0-alpha.1.25227.1 + 10.0.0-alpha.1.25227.1 + 10.0.0-alpha.1.25227.1 - 10.0.0-alpha.1.25218.5 - 10.0.0-alpha.1.25218.5 - 10.0.0-alpha.1.25218.5 - 10.0.0-alpha.1.25218.5 + 10.0.0-alpha.1.25227.1 + 10.0.0-alpha.1.25227.1 + 10.0.0-alpha.1.25227.1 + 10.0.0-alpha.1.25227.1 10.0.0-alpha.1.25222.1 10.0.0-alpha.1.25222.1 @@ -41,14 +41,14 @@ 10.0.0-alpha.1.25222.1 10.0.0-alpha.1.25222.1 - 19.1.0-alpha.1.25218.2 - 19.1.0-alpha.1.25218.2 - 19.1.0-alpha.1.25218.2 - 19.1.0-alpha.1.25218.2 - 19.1.0-alpha.1.25218.2 - 19.1.0-alpha.1.25218.2 - 19.1.0-alpha.1.25218.2 - 19.1.0-alpha.1.25218.2 + 19.1.0-alpha.1.25228.1 + 19.1.0-alpha.1.25228.1 + 19.1.0-alpha.1.25228.1 + 19.1.0-alpha.1.25228.1 + 19.1.0-alpha.1.25228.1 + 19.1.0-alpha.1.25228.1 + 19.1.0-alpha.1.25228.1 + 19.1.0-alpha.1.25228.1 10.0.0-alpha.1.25218.4 @@ -57,11 +57,11 @@ release - 10.0.0-beta.25223.119 - 10.0.0-beta.25223.119 - 10.0.0-beta.25223.119 - 10.0.0-beta.25223.119 - 10.0.0-beta.25223.119 + 10.0.0-beta.25251.105 + 10.0.0-beta.25251.105 + 10.0.0-beta.25251.105 + 10.0.0-beta.25251.105 + 10.0.0-beta.25251.105 1.1.87-gba258badda diff --git a/src/emsdk/eng/common/core-templates/job/source-build.yml b/src/emsdk/eng/common/core-templates/job/source-build.yml index 05f7ad6ef0d..d805d5faeb9 100644 --- a/src/emsdk/eng/common/core-templates/job/source-build.yml +++ b/src/emsdk/eng/common/core-templates/job/source-build.yml @@ -27,6 +27,8 @@ parameters: # Specifies the build script to invoke to perform the build in the repo. The default # './build.sh' should work for typical Arcade repositories, but this is customizable for # difficult situations. + # buildArguments: '' + # Specifies additional build arguments to pass to the build script. # jobProperties: {} # A list of job properties to inject at the top level, for potential extensibility beyond # container and pool. diff --git a/src/emsdk/eng/common/core-templates/jobs/jobs.yml b/src/emsdk/eng/common/core-templates/jobs/jobs.yml index e653d19971c..bf35b78faa6 100644 --- a/src/emsdk/eng/common/core-templates/jobs/jobs.yml +++ b/src/emsdk/eng/common/core-templates/jobs/jobs.yml @@ -96,7 +96,7 @@ jobs: ${{ parameter.key }}: ${{ parameter.value }} - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - - ${{ if or(eq(parameters.enablePublishBuildAssets, true), eq(parameters.artifacts.publish.manifests, 'true'), ne(parameters.artifacts.publish.manifests, '')) }}: + - ${{ if or(eq(parameters.enablePublishBuildAssets, true), eq(parameters.artifacts.publish.manifests, 'true'), ne(parameters.artifacts.publish.manifests, ''), eq(parameters.isAssetlessBuild, true)) }}: - template: ../job/publish-build-assets.yml parameters: is1ESPipeline: ${{ parameters.is1ESPipeline }} @@ -112,7 +112,7 @@ jobs: - Source_Build_Complete runAsPublic: ${{ parameters.runAsPublic }} - publishAssetsImmediately: ${{ parameters.publishAssetsImmediately }} + publishAssetsImmediately: ${{ or(parameters.publishAssetsImmediately, parameters.isAssetlessBuild) }} isAssetlessBuild: ${{ parameters.isAssetlessBuild }} enablePublishBuildArtifacts: ${{ parameters.enablePublishBuildArtifacts }} artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} diff --git a/src/emsdk/eng/common/core-templates/jobs/source-build.yml b/src/emsdk/eng/common/core-templates/jobs/source-build.yml index a10ccfbee6d..df24c948ba1 100644 --- a/src/emsdk/eng/common/core-templates/jobs/source-build.yml +++ b/src/emsdk/eng/common/core-templates/jobs/source-build.yml @@ -14,7 +14,7 @@ parameters: # This is the default platform provided by Arcade, intended for use by a managed-only repo. defaultManagedPlatform: name: 'Managed' - container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream9' + container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream-10-amd64' # Defines the platforms on which to run build jobs. One job is created for each platform, and the # object in this array is sent to the job template as 'platform'. If no platforms are specified, diff --git a/src/emsdk/eng/common/core-templates/steps/source-build.yml b/src/emsdk/eng/common/core-templates/steps/source-build.yml index d65c222c069..c6b9ef51ac6 100644 --- a/src/emsdk/eng/common/core-templates/steps/source-build.yml +++ b/src/emsdk/eng/common/core-templates/steps/source-build.yml @@ -84,6 +84,7 @@ steps: ${{ coalesce(parameters.platform.buildScript, './build.sh') }} --ci \ --configuration $buildConfig \ --restore --build --pack $publishArgs -bl \ + ${{ parameters.platform.buildArguments }} \ $officialBuildArgs \ $internalRuntimeDownloadArgs \ $internalRestoreArgs \ @@ -93,9 +94,7 @@ steps: $portableBuildArgs \ /p:DotNetBuildSourceOnly=true \ /p:DotNetBuildRepo=true \ - /p:AssetManifestFileName=$assetManifestFileName \ - /p:SetUpSourceBuildIntermediateNupkgCache=false \ - /p:ReportPrebuiltUsage=false + /p:AssetManifestFileName=$assetManifestFileName displayName: Build # Upload build logs for diagnosis. @@ -122,14 +121,3 @@ steps: continueOnError: true condition: succeededOrFailed() sbomEnabled: false # we don't need SBOM for logs - -# Manually inject component detection so that we can ignore the source build upstream cache, which contains -# a nupkg cache of input packages (a local feed). -# This path must match the upstream cache path in property 'CurrentRepoSourceBuiltNupkgCacheDir' -# in src\Microsoft.DotNet.Arcade.Sdk\tools\SourceBuild\SourceBuildArcade.targets -- template: /eng/common/core-templates/steps/component-governance.yml - parameters: - displayName: Component Detection (Exclude upstream cache) - is1ESPipeline: ${{ parameters.is1ESPipeline }} - componentGovernanceIgnoreDirectories: '$(Build.SourcesDirectory)/artifacts/sb/src/artifacts/obj/source-built-upstream-cache' - disableComponentGovernance: ${{ eq(variables['System.TeamProject'], 'public') }} diff --git a/src/emsdk/eng/common/core-templates/steps/source-index-stage1-publish.yml b/src/emsdk/eng/common/core-templates/steps/source-index-stage1-publish.yml index 473a22c4719..99c2326fc19 100644 --- a/src/emsdk/eng/common/core-templates/steps/source-index-stage1-publish.yml +++ b/src/emsdk/eng/common/core-templates/steps/source-index-stage1-publish.yml @@ -1,6 +1,6 @@ parameters: - sourceIndexUploadPackageVersion: 2.0.0-20240522.1 - sourceIndexProcessBinlogPackageVersion: 1.0.1-20240522.1 + sourceIndexUploadPackageVersion: 2.0.0-20250425.2 + sourceIndexProcessBinlogPackageVersion: 1.0.1-20250425.2 sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json binlogPath: artifacts/log/Debug/Build.binlog diff --git a/src/emsdk/global.json b/src/emsdk/global.json index 800fcde9cba..ae0b5fa127e 100644 --- a/src/emsdk/global.json +++ b/src/emsdk/global.json @@ -3,8 +3,8 @@ "dotnet": "10.0.100-preview.3.25201.16" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25223.119", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25223.119", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25251.105", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25251.105", "Microsoft.Build.Traversal": "3.4.0" } } diff --git a/src/fsharp/proto.proj b/src/fsharp/proto.proj index eb0814976ea..69497f54883 100644 --- a/src/fsharp/proto.proj +++ b/src/fsharp/proto.proj @@ -7,7 +7,8 @@ - + + diff --git a/src/msbuild/.github/workflows/labeler-build-predictor.yml b/src/msbuild/.github/workflows/labeler-build-predictor.yml deleted file mode 100644 index 8a12b312db0..00000000000 --- a/src/msbuild/.github/workflows/labeler-build-predictor.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: "Labeler: Build Predictor App" - -on: - # Allow dispatching the workflow via the Actions UI - workflow_dispatch: - inputs: - rebuild: - description: "Force a rebuild of the app" - type: boolean - -jobs: - build-predictor: - permissions: - actions: write - uses: dotnet/issue-labeler/.github/workflows/build-predictor.yml@f0c098669828a134c0313adf3f58c1909e555d86 # v1.0.1 - with: - rebuild: ${{ inputs.rebuild }} diff --git a/src/msbuild/.github/workflows/labeler-cache-retention.yml b/src/msbuild/.github/workflows/labeler-cache-retention.yml index 26a09ee7244..9669e31da69 100644 --- a/src/msbuild/.github/workflows/labeler-cache-retention.yml +++ b/src/msbuild/.github/workflows/labeler-cache-retention.yml @@ -1,13 +1,35 @@ +# Regularly restore the prediction models from cache to prevent cache eviction name: "Labeler: Cache Retention" +# For more information about GitHub's action cache limits and eviction policy, see: +# https://docs.github.com/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy + on: schedule: - cron: "10 3 * * *" # 3:10 every day (arbitrary time daily, modified to different values in each repository) workflow_dispatch: + inputs: + cache_key: + description: "The cache key suffix to use for restoring the model from cache. Defaults to 'ACTIVE'." + required: true + default: "ACTIVE" + +env: + CACHE_KEY: ${{ inputs.cache_key || 'ACTIVE' }} jobs: - cache-retention: - # Do not run the workflow on forks outside the 'dotnet' org - if: ${{ github.repository_owner == 'dotnet' }} - uses: dotnet/issue-labeler/.github/workflows/cache-retention.yml@f0c098669828a134c0313adf3f58c1909e555d86 # v1.0.1 + restore-cache: + # Do not automatically run the workflow on forks outside the 'dotnet' org + if: ${{ github.event_name == 'workflow_dispatch' || github.repository_owner == 'dotnet' }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + type: ["issues", "pulls"] + steps: + - uses: dotnet/issue-labeler/restore@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: ${{ matrix.type }} + cache_key: ${{ env.CACHE_KEY }} + fail-on-cache-miss: true diff --git a/src/msbuild/.github/workflows/labeler-predict-issues.yml b/src/msbuild/.github/workflows/labeler-predict-issues.yml index e560988577d..95cbf2512a8 100644 --- a/src/msbuild/.github/workflows/labeler-predict-issues.yml +++ b/src/msbuild/.github/workflows/labeler-predict-issues.yml @@ -1,33 +1,53 @@ -name: "Labeler: Predict Issue Labels" +# Predict labels for Issues using a trained model +name: "Labeler: Predict (Issues)" on: - # Only automatically predict area labels when issues are originally opened + # Only automatically predict area labels when issues are first opened issues: types: opened # Allow dispatching the workflow via the Actions UI, specifying ranges of numbers workflow_dispatch: inputs: - issue_numbers: - description: "Issue Numbers (comma-separated list of ranges)" - type: string - model_cache_key: - description: "The cache key suffix to use for loading the model" - type: string + issues: + description: "Issue Numbers (comma-separated list of ranges)." required: true - default: "LIVE" + cache_key: + description: "The cache key suffix to use for restoring the model. Defaults to 'ACTIVE'." + required: true + default: "ACTIVE" + +env: + # Do not allow failure for jobs triggered automatically (as this causes red noise on the workflows list) + ALLOW_FAILURE: ${{ github.event_name == 'workflow_dispatch' }} + + LABEL_PREFIX: "Area: " + THRESHOLD: 0.40 jobs: - predict-issues: - # Do not run the workflow on forks outside the 'dotnet' org - if: ${{ github.repository_owner == 'dotnet' && (inputs.issue_numbers || github.event.issue.number) }} + predict-issue-label: + # Do not automatically run the workflow on forks outside the 'dotnet' org + if: ${{ github.event_name == 'workflow_dispatch' || github.repository_owner == 'dotnet' }} + runs-on: ubuntu-latest permissions: issues: write - uses: dotnet/issue-labeler/.github/workflows/predict-issues.yml@f0c098669828a134c0313adf3f58c1909e555d86 # v1.0.1 - with: - model_cache_key: ${{ inputs.model_cache_key }} - issue_numbers: ${{ inputs.issue_numbers || github.event.issue.number }} - label_prefix: "Area: " - threshold: 0.40 - # default_label: "needs-area-label" + steps: + - name: "Restore issues model from cache" + id: restore-model + uses: dotnet/issue-labeler/restore@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: issues + fail-on-cache-miss: ${{ env.ALLOW_FAILURE }} + quiet: true + - name: "Predict issue labels" + id: prediction + if: ${{ steps.restore-model.outputs.cache-hit == 'true' }} + uses: dotnet/issue-labeler/predict@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + issues: ${{ inputs.issues || github.event.issue.number }} + label_prefix: ${{ env.LABEL_PREFIX }} + threshold: ${{ env.THRESHOLD }} + env: + GITHUB_TOKEN: ${{ github.token }} + continue-on-error: ${{ !env.ALLOW_FAILURE }} diff --git a/src/msbuild/.github/workflows/labeler-predict-pulls.yml b/src/msbuild/.github/workflows/labeler-predict-pulls.yml index fba01a5d324..17b345fcd41 100644 --- a/src/msbuild/.github/workflows/labeler-predict-pulls.yml +++ b/src/msbuild/.github/workflows/labeler-predict-pulls.yml @@ -1,4 +1,5 @@ -name: "Labeler: Predict Pull Labels" +# Predict labels for Pull Requests using a trained model +name: "Labeler: Predict (Pulls)" on: # Per to the following documentation: @@ -13,6 +14,8 @@ on: # Only automatically predict area labels when pull requests are first opened pull_request_target: types: opened + + # Configure the branches that need to have PRs labeled branches: - 'main' - 'vs*' @@ -20,25 +23,45 @@ on: # Allow dispatching the workflow via the Actions UI, specifying ranges of numbers workflow_dispatch: inputs: - pull_numbers: - description: "Pull Numbers (comma-separated list of ranges)" - type: string - model_cache_key: - description: "The cache key suffix to use for loading the model" - type: string + pulls: + description: "Pull Request Numbers (comma-separated list of ranges)." + required: true + cache_key: + description: "The cache key suffix to use for restoring the model. Defaults to 'ACTIVE'." required: true - default: "LIVE" + default: "ACTIVE" + +env: + # Do not allow failure for jobs triggered automatically (this can block PR merge) + ALLOW_FAILURE: ${{ github.event_name == 'workflow_dispatch' }} + + LABEL_PREFIX: "Area: " + THRESHOLD: 0.40 jobs: - predict-pulls: - # Do not run the workflow on forks outside the 'dotnet' org - if: ${{ github.repository_owner == 'dotnet' && (inputs.pull_numbers || github.event.number) }} + predict-pull-label: + # Do not automatically run the workflow on forks outside the 'dotnet' org + if: ${{ github.event_name == 'workflow_dispatch' || github.repository_owner == 'dotnet' }} + runs-on: ubuntu-latest permissions: pull-requests: write - uses: dotnet/issue-labeler/.github/workflows/predict-pulls.yml@f0c098669828a134c0313adf3f58c1909e555d86 # v1.0.1 - with: - model_cache_key: ${{ inputs.model_cache_key }} - pull_numbers: ${{ inputs.pull_numbers || github.event.number }} - label_prefix: "Area: " - threshold: 0.40 - # default_label: "needs-area-label" + steps: + - name: "Restore pulls model from cache" + id: restore-model + uses: dotnet/issue-labeler/restore@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: pulls + fail-on-cache-miss: ${{ env.ALLOW_FAILURE }} + quiet: true + + - name: "Predict pull labels" + id: prediction + if: ${{ steps.restore-model.outputs.cache-hit == 'true' }} + uses: dotnet/issue-labeler/predict@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + pulls: ${{ inputs.pulls || github.event.number }} + label_prefix: ${{ env.LABEL_PREFIX }} + threshold: ${{ env.THRESHOLD }} + env: + GITHUB_TOKEN: ${{ github.token }} + continue-on-error: ${{ !env.ALLOW_FAILURE }} diff --git a/src/msbuild/.github/workflows/labeler-promote.yml b/src/msbuild/.github/workflows/labeler-promote.yml index 97f40afa8f1..f5208c5191f 100644 --- a/src/msbuild/.github/workflows/labeler-promote.yml +++ b/src/msbuild/.github/workflows/labeler-promote.yml @@ -1,42 +1,49 @@ -name: "Labeler: Promote Models" +# Promote a model from staging to 'ACTIVE', backing up the currently 'ACTIVE' model +name: "Labeler: Promotion" on: # Dispatched via the Actions UI, promotes the staged models from - # a staging slot into the prediction environment + # a staged slot into the prediction environment workflow_dispatch: inputs: - promote_issues: + issues: description: "Issues: Promote Model" type: boolean required: true - promote_pulls: + pulls: description: "Pulls: Promote Model" type: boolean required: true - model_cache_key: - description: "The cache key suffix to promote into the 'LIVE' cache" - type: string + staged_key: + description: "The cache key suffix to use for promoting a staged model to 'ACTIVE'. Defaults to 'staged'." required: true - default: "staging" - backup_cache_key: - description: "The cache key suffix to use for backing up the currently promoted model" - type: string + default: "staged" + backup_key: + description: "The cache key suffix to use for backing up the currently active model. Defaults to 'backup'." default: "backup" permissions: actions: write jobs: - labeler-promote-issues: - if: ${{ inputs.promote_issues }} - uses: dotnet/issue-labeler/.github/workflows/promote-issues.yml@f0c098669828a134c0313adf3f58c1909e555d86 # v1.0.1 - with: - model_cache_key: ${{ inputs.model_cache_key }} - backup_cache_key: ${{ inputs.backup_cache_key }} + promote-issues: + if: ${{ inputs.issues }} + runs-on: ubuntu-latest + steps: + - name: "Promote Model for Issues" + uses: dotnet/issue-labeler/promote@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: "issues" + staged_key: ${{ inputs.staged_key }} + backup_key: ${{ inputs.backup_key }} - labeler-promote-pulls: - if: ${{ inputs.promote_pulls }} - uses: dotnet/issue-labeler/.github/workflows/promote-pulls.yml@f0c098669828a134c0313adf3f58c1909e555d86 # v1.0.1 - with: - model_cache_key: ${{ inputs.model_cache_key }} - backup_cache_key: ${{ inputs.backup_cache_key }} + promote-pulls: + if: ${{ inputs.pulls }} + runs-on: ubuntu-latest + steps: + - name: "Promote Model for Pull Requests" + uses: dotnet/issue-labeler/promote@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: "pulls" + staged_key: ${{ inputs.staged_key }} + backup_key: ${{ inputs.backup_key }} diff --git a/src/msbuild/.github/workflows/labeler-train.yml b/src/msbuild/.github/workflows/labeler-train.yml index 90095eb88ba..cbfa071956f 100644 --- a/src/msbuild/.github/workflows/labeler-train.yml +++ b/src/msbuild/.github/workflows/labeler-train.yml @@ -1,63 +1,160 @@ -name: "Labeler: Train Models" +# Train the Issues and Pull Requests models for label prediction +name: "Labeler: Training" on: - # Dispatched via the Actions UI, stages new models for promotion consideration - # Each step of the workflow can be run independently: Download, Train, and Test workflow_dispatch: inputs: - download_issues: - description: "Issues: Download Data" - type: boolean - default: true - train_issues: - description: "Issues: Train Model" - type: boolean - default: true - test_issues: - description: "Issues: Test Model" - type: boolean - default: true - download_pulls: - description: "Pulls: Download Data" - type: boolean - default: true - train_pulls: - description: "Pulls: Train Model" - type: boolean - default: true - test_pulls: - description: "Pulls: Test Model" - type: boolean - default: true - repository: - description: "Repository to train the models from" - - data_limit: - description: "Max number of items to include in the model" - type: number + type: + description: "Issues or Pull Requests" + type: choice + required: true + default: "Both" + options: + - "Both" + - "Issues" + - "Pull Requests" + steps: + description: "Training Steps" + type: choice + required: true + default: "All" + options: + - "All" + - "Download Data" + - "Train Model" + - "Test Model" + + limit: + description: "Max number of items to download for training/testing the model (newest items are used). Defaults to the max number of pages times the page size." + type: number + page_size: + description: "Number of items per page in GitHub API requests. Defaults to 100 for issues, 25 for pull requests." + type: number + page_limit: + description: "Maximum number of pages to download for training/testing the model. Defaults to 1000 for issues, 4000 for pull requests." + type: number cache_key_suffix: - description: "The cache key suffix to use for staging data/models (use 'LIVE' to bypass staging)" - type: string + description: "The cache key suffix to use for staged data/models (use 'ACTIVE' to bypass staging). Defaults to 'staged'." required: true - default: "staging" + default: "staged" + +env: + CACHE_KEY: ${{ inputs.cache_key_suffix }} + REPOSITORY: ${{ github.repository }} + LABEL_PREFIX: "Area: " + THRESHOLD: "0.40" + LIMIT: ${{ inputs.limit }} + PAGE_SIZE: ${{ inputs.page_size }} + PAGE_LIMIT: ${{ inputs.page_limit }} jobs: - labeler-train: + download-issues: + if: ${{ contains(fromJSON('["Both", "Issues"]'), inputs.type) && contains(fromJSON('["All", "Download Data"]'), inputs.steps) }} + runs-on: ubuntu-latest + permissions: + issues: read + steps: + - name: "Download Issues" + uses: dotnet/issue-labeler/download@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: "issues" + cache_key: ${{ env.CACHE_KEY }} + repository: ${{ env.REPOSITORY }} + label_prefix: ${{ env.LABEL_PREFIX }} + limit: ${{ env.LIMIT }} + page_size: ${{ env.PAGE_SIZE }} + page_limit: ${{ env.PAGE_LIMIT }} + excluded_authors: ${{ env.EXCLUDED_AUTHORS }} + env: + GITHUB_TOKEN: ${{ github.token }} + + download-pulls: + if: ${{ contains(fromJSON('["Both", "Pull Requests"]'), inputs.type) && contains(fromJSON('["All", "Download Data"]'), inputs.steps) }} + runs-on: ubuntu-latest + permissions: + pull-requests: read + steps: + - name: "Download Pull Requests" + uses: dotnet/issue-labeler/download@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: "pulls" + cache_key: ${{ env.CACHE_KEY }} + repository: ${{ env.REPOSITORY }} + label_prefix: ${{ env.LABEL_PREFIX }} + limit: ${{ env.LIMIT }} + page_size: ${{ env.PAGE_SIZE }} + page_limit: ${{ env.PAGE_LIMIT }} + excluded_authors: ${{ env.EXCLUDED_AUTHORS }} + env: + GITHUB_TOKEN: ${{ github.token }} + + train-issues: + if: ${{ always() && contains(fromJSON('["Both", "Issues"]'), inputs.type) && contains(fromJSON('["All", "Train Model"]'), inputs.steps) && contains(fromJSON('["success", "skipped"]'), needs.download-issues.result) }} + runs-on: ubuntu-latest + permissions: {} + needs: download-issues + steps: + - name: "Train Model for Issues" + uses: dotnet/issue-labeler/train@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: "issues" + data_cache_key: ${{ env.CACHE_KEY }} + model_cache_key: ${{ env.CACHE_KEY }} + + train-pulls: + if: ${{ always() && contains(fromJSON('["Both", "Pull Requests"]'), inputs.type) && contains(fromJSON('["All", "Train Model"]'), inputs.steps) && contains(fromJSON('["success", "skipped"]'), needs.download-pulls.result) }} + runs-on: ubuntu-latest + permissions: {} + needs: download-pulls + steps: + - name: "Train Model for Pull Requests" + uses: dotnet/issue-labeler/train@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: "pulls" + data_cache_key: ${{ env.CACHE_KEY }} + model_cache_key: ${{ env.CACHE_KEY }} + + test-issues: + if: ${{ always() && contains(fromJSON('["Both", "Issues"]'), inputs.type) && contains(fromJSON('["All", "Test Model"]'), inputs.steps) && contains(fromJSON('["success", "skipped"]'), needs.train-issues.result) }} + runs-on: ubuntu-latest permissions: issues: read + needs: train-issues + steps: + - name: "Test Model for Issues" + uses: dotnet/issue-labeler/test@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: "issues" + cache_key: ${{ env.CACHE_KEY }} + repository: ${{ env.REPOSITORY }} + label_prefix: ${{ env.LABEL_PREFIX }} + threshold: ${{ env.THRESHOLD }} + limit: ${{ env.LIMIT }} + page_size: ${{ env.PAGE_SIZE }} + page_limit: ${{ env.PAGE_LIMIT }} + excluded_authors: ${{ env.EXCLUDED_AUTHORS }} + env: + GITHUB_TOKEN: ${{ github.token }} + + test-pulls: + if: ${{ always() && contains(fromJSON('["Both", "Pull Requests"]'), inputs.type) && contains(fromJSON('["All", "Test Model"]'), inputs.steps) && contains(fromJSON('["success", "skipped"]'), needs.train-pulls.result) }} + runs-on: ubuntu-latest + permissions: pull-requests: read - actions: write - uses: dotnet/issue-labeler/.github/workflows/train.yml@f0c098669828a134c0313adf3f58c1909e555d86 # v1.0.1 - with: - download_issues: ${{ inputs.download_issues }} - train_issues: ${{ inputs.train_issues }} - test_issues: ${{ inputs.test_issues }} - download_pulls: ${{ inputs.download_pulls }} - train_pulls: ${{ inputs.train_pulls }} - test_pulls: ${{ inputs.test_pulls }} - data_limit: ${{ inputs.data_limit && fromJSON(inputs.data_limit) || 0 }} - cache_key_suffix: ${{ inputs.cache_key_suffix }} - repository: ${{ inputs.repository }} - label_prefix: "Area: " - threshold: 0.40 + needs: train-pulls + steps: + - name: "Test Model for Pull Requests" + uses: dotnet/issue-labeler/test@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: "pulls" + cache_key: ${{ env.CACHE_KEY }} + repository: ${{ env.REPOSITORY }} + label_prefix: ${{ env.LABEL_PREFIX }} + threshold: ${{ env.THRESHOLD }} + limit: ${{ env.LIMIT }} + page_size: ${{ env.PAGE_SIZE }} + page_limit: ${{ env.PAGE_LIMIT }} + excluded_authors: ${{ env.EXCLUDED_AUTHORS }} + env: + GITHUB_TOKEN: ${{ github.token }} diff --git a/src/msbuild/eng/Version.Details.xml b/src/msbuild/eng/Version.Details.xml index e8e5aa24b92..aa110fe0421 100644 --- a/src/msbuild/eng/Version.Details.xml +++ b/src/msbuild/eng/Version.Details.xml @@ -142,13 +142,13 @@ https://github.com/nuget/nuget.client 0da03caba83448ee887f0f1846dd05e1f1705d45 - + https://github.com/dotnet/roslyn - 49152f06cf4a4500311f1c515d86a660dd940c0a + 871ef6369443071681de3351d30f41ea78ab48e6 - + https://github.com/dotnet/roslyn - 49152f06cf4a4500311f1c515d86a660dd940c0a + 871ef6369443071681de3351d30f41ea78ab48e6 diff --git a/src/msbuild/eng/Versions.props b/src/msbuild/eng/Versions.props index 511b84764d7..e07f8a4a03c 100644 --- a/src/msbuild/eng/Versions.props +++ b/src/msbuild/eng/Versions.props @@ -81,9 +81,8 @@ $([System.Text.RegularExpressions.Regex]::Match($([System.IO.File]::ReadAllText('$(MSBuildThisFileDirectory)..\global.json')), '"dotnet": "([^"]*)"').Groups.get_Item(1)) 4.2.0-1.22102.8 9.0.0-beta.25208.6 - 4.14.0-3.25225.7 + 4.14.0-3.25229.6 6.14.0-rc.116 - 9.0.200-preview.0.24603.3 diff --git a/src/msbuild/src/Build.UnitTests/BackEnd/SdkResolverService_Tests.cs b/src/msbuild/src/Build.UnitTests/BackEnd/SdkResolverService_Tests.cs index 10a1c5dcd6c..8200c364d2a 100644 --- a/src/msbuild/src/Build.UnitTests/BackEnd/SdkResolverService_Tests.cs +++ b/src/msbuild/src/Build.UnitTests/BackEnd/SdkResolverService_Tests.cs @@ -75,6 +75,33 @@ public void AssertAllResolverErrorsLoggedWhenSdkNotResolved() _logger.Warnings.Select(i => i.Message).ShouldBe(new[] { "WARNING4", "WARNING2" }); } + [Fact] + public void AssertSingleResolverErrorLoggedWhenSdkNotResolved() + { + var service = new SdkResolverService(); + + // Use mock loader that only provides a single resolver + service.InitializeForTests(new MockLoaderStrategy(includeSingleResolverOnly: true)); + + var sdk = new SdkReference("notfound", "referencedVersion", "minimumVersion"); + + var result = service.ResolveSdk(BuildEventContext.InvalidSubmissionId, sdk, _loggingContext, new MockElementLocation("file"), "sln", "projectPath", interactive: false, isRunningInVisualStudio: false, failOnUnresolvedSdk: true); + + result.Success.ShouldBeFalse(); + result.ShouldNotBeNull(); + result.SdkReference.ShouldNotBeNull(); + result.SdkReference.Name.ShouldBe("notfound"); + + // Check that only the simplified error (no MSBuild wrapper) is logged + _logger.Errors.Count.ShouldBe(1); + _logger.Errors[0].Message.ShouldBe( + ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword( + "SingleResolverFailedToResolveSDK", + "notfound", + "MockSdkResolver1", + "ERROR1")); + } + [Fact] public void AssertResolutionWarnsIfResolvedVersionIsDifferentFromReferencedVersion() { @@ -743,8 +770,14 @@ private sealed class MockLoaderStrategy : SdkResolverLoader public bool ResolversHaveBeenLoaded { get; private set; } = false; public bool ManifestsHaveBeenLoaded { get; private set; } = false; - public MockLoaderStrategy(bool includeErrorResolver = false, bool includeResolversWithPatterns = false, bool includeDefaultResolver = false) : this() + public MockLoaderStrategy(bool includeErrorResolver = false, bool includeResolversWithPatterns = false, bool includeDefaultResolver = false , bool includeSingleResolverOnly = false) : this() { + if (includeSingleResolverOnly) + { + _resolvers = new List { new MockSdkResolver1() }; + return; // Exit early so other ones aren't added + } + if (includeErrorResolver) { _resolvers.Add(new MockSdkResolverThrows()); diff --git a/src/msbuild/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/msbuild/src/Build/BackEnd/BuildManager/BuildManager.cs index 667e0ba6616..fa6ae4bbbfd 100644 --- a/src/msbuild/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/msbuild/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -678,7 +678,7 @@ IEnumerable AppendDebuggingLoggers(IEnumerable loggers) var logger = new BinaryLogger { Parameters = binlogPath }; - return (loggers ?? [logger]); + return (loggers ?? []).Concat([logger]); } void InitializeCaches() diff --git a/src/msbuild/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs b/src/msbuild/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs index d892518e9ea..bd8e221c3dd 100644 --- a/src/msbuild/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs +++ b/src/msbuild/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs @@ -15,6 +15,7 @@ using Microsoft.Build.Shared; using Microsoft.Build.Shared.Debugging; using Microsoft.Build.TelemetryInfra; +using Microsoft.NET.StringTools; using BuildAbortedException = Microsoft.Build.Exceptions.BuildAbortedException; #nullable disable @@ -314,6 +315,8 @@ public void CleanupForBuild() _requestsByGlobalRequestId.Clear(); _unsubmittedRequests.Clear(); _unresolvedConfigurations.ClearConfigurations(); + Strings.ClearCachedStrings(); + ChangeStatus(BuildRequestEngineStatus.Uninitialized); } } @@ -1131,8 +1134,8 @@ private void IssueBuildRequests(BuildRequestEntry issuingEntry, FullyQualifiedBu // to the entry rather than a series of them. lock (issuingEntry.GlobalLock) { - var existingResultsToReport = new List(); - var unresolvedConfigurationsAdded = new HashSet(); + List existingResultsToReport = null; + HashSet unresolvedConfigurationsAdded = null; foreach (FullyQualifiedBuildRequest request in newRequests) { @@ -1157,6 +1160,7 @@ private void IssueBuildRequests(BuildRequestEntry issuingEntry, FullyQualifiedBu // Not waiting for it request.Config.ConfigurationId = GetNextUnresolvedConfigurationId(); _unresolvedConfigurations.AddConfiguration(request.Config); + unresolvedConfigurationsAdded ??= new HashSet(); unresolvedConfigurationsAdded.Add(request.Config.ConfigurationId); } else @@ -1235,6 +1239,7 @@ private void IssueBuildRequests(BuildRequestEntry issuingEntry, FullyQualifiedBu // Can't report the result directly here, because that could cause the request to go from // Waiting to Ready. + existingResultsToReport ??= new List(); existingResultsToReport.Add(response.Results); } else @@ -1246,9 +1251,12 @@ private void IssueBuildRequests(BuildRequestEntry issuingEntry, FullyQualifiedBu } // If we have any results we had to report, do so now. - foreach (BuildResult existingResult in existingResultsToReport) + if (existingResultsToReport is not null) { - issuingEntry.ReportResult(existingResult); + foreach (BuildResult existingResult in existingResultsToReport) + { + issuingEntry.ReportResult(existingResult); + } } // Issue any configuration requests we may still need. @@ -1257,16 +1265,23 @@ private void IssueBuildRequests(BuildRequestEntry issuingEntry, FullyQualifiedBu { foreach (BuildRequestConfiguration unresolvedConfigurationToIssue in unresolvedConfigurationsToIssue) { - unresolvedConfigurationsAdded.Remove(unresolvedConfigurationToIssue.ConfigurationId); + if (unresolvedConfigurationsAdded is not null) + { + unresolvedConfigurationsAdded.Remove(unresolvedConfigurationToIssue.ConfigurationId); + } + IssueConfigurationRequest(unresolvedConfigurationToIssue); } } // Remove any configurations we ended up not waiting for, otherwise future requests will think we are still waiting for them // and will never get submitted. - foreach (int unresolvedConfigurationId in unresolvedConfigurationsAdded) + if (unresolvedConfigurationsAdded is not null) { - _unresolvedConfigurations.RemoveConfiguration(unresolvedConfigurationId); + foreach (int unresolvedConfigurationId in unresolvedConfigurationsAdded) + { + _unresolvedConfigurations.RemoveConfiguration(unresolvedConfigurationId); + } } // Finally, if we can issue build requests, do so. diff --git a/src/msbuild/src/Build/BackEnd/Components/SdkResolution/SdkResolverService.cs b/src/msbuild/src/Build/BackEnd/Components/SdkResolution/SdkResolverService.cs index 1d6ec92f64c..7318e57e900 100644 --- a/src/msbuild/src/Build/BackEnd/Components/SdkResolution/SdkResolverService.cs +++ b/src/msbuild/src/Build/BackEnd/Components/SdkResolution/SdkResolverService.cs @@ -250,7 +250,16 @@ private SdkResult ResolveSdkUsingResolversWithPatternsFirst(int submissionId, Sd if (failOnUnresolvedSdk) { - loggingContext.LogError(new BuildEventFileInfo(sdkReferenceLocation), "FailedToResolveSDK", sdk.Name, string.Join($"{Environment.NewLine} ", errors)); + if (resolvers.Count == 1) // Check if only one resolver was used + { + // Log the single resolver's error message directly + loggingContext.LogError(new BuildEventFileInfo(sdkReferenceLocation), "SingleResolverFailedToResolveSDK", sdk.Name, resolvers[0].Name, string.Join(Environment.NewLine, errors)); + } + else + { + // Log the error with the MSBuild wrapper + loggingContext.LogError(new BuildEventFileInfo(sdkReferenceLocation), "FailedToResolveSDK", sdk.Name, string.Join($"{Environment.NewLine} ", errors)); + } } LogWarnings(loggingContext, sdkReferenceLocation, warnings); diff --git a/src/msbuild/src/Build/Instance/TaskRegistry.cs b/src/msbuild/src/Build/Instance/TaskRegistry.cs index 508cb7483b6..c4023835131 100644 --- a/src/msbuild/src/Build/Instance/TaskRegistry.cs +++ b/src/msbuild/src/Build/Instance/TaskRegistry.cs @@ -1188,7 +1188,7 @@ internal class Stats() public void ExecutionStarted() { - _memoryConsumptionOnStart = GC.GetTotalMemory(false); + _memoryConsumptionOnStart = GetMemoryAllocated(); _executedSw.Start(); ExecutedCount++; } @@ -1196,7 +1196,16 @@ public void ExecutionStarted() public void ExecutionStopped() { _executedSw.Stop(); - TotalMemoryConsumption += GC.GetTotalMemory(false) - _memoryConsumptionOnStart; + TotalMemoryConsumption += GetMemoryAllocated() - _memoryConsumptionOnStart; + } + + private static long GetMemoryAllocated() + { +#if NET + return GC.GetTotalAllocatedBytes(false); +#else + return GC.GetTotalMemory(false); +#endif } public void Reset() diff --git a/src/msbuild/src/Build/Resources/Strings.resx b/src/msbuild/src/Build/Resources/Strings.resx index f6b9b047fea..71a53635fdd 100644 --- a/src/msbuild/src/Build/Resources/Strings.resx +++ b/src/msbuild/src/Build/Resources/Strings.resx @@ -1340,6 +1340,9 @@ The SDK resolver "{0}" failed while attempting to resolve the SDK "{1}". Exception: "{2}" + + SDK '{0}' could not be resolved by the SDK resolver '{1}'. {2} + Could not resolve SDK "{0}". Exactly one of the probing messages below indicates why we could not resolve the SDK. Investigate and resolve that message to correctly specify the SDK. {1} diff --git a/src/msbuild/src/Build/Resources/xlf/Strings.cs.xlf b/src/msbuild/src/Build/Resources/xlf/Strings.cs.xlf index 57283f86965..03650f88f89 100644 --- a/src/msbuild/src/Build/Resources/xlf/Strings.cs.xlf +++ b/src/msbuild/src/Build/Resources/xlf/Strings.cs.xlf @@ -860,6 +860,11 @@ Chyby: {3} Překladač sady SDK „{0}“ vrátil hodnotu null. + + SDK '{0}' could not be resolved by the SDK resolver '{1}'. {2} + Sadu SDK {0} se nepodařilo vyřešit pomocí překladače sady SDK {1}. {2} + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: Projekt {0} přeskočil omezení izolace grafu v odkazovaném projektu {1}. diff --git a/src/msbuild/src/Build/Resources/xlf/Strings.de.xlf b/src/msbuild/src/Build/Resources/xlf/Strings.de.xlf index 985615208fb..2ad593ea66a 100644 --- a/src/msbuild/src/Build/Resources/xlf/Strings.de.xlf +++ b/src/msbuild/src/Build/Resources/xlf/Strings.de.xlf @@ -860,6 +860,11 @@ Fehler: {3} Der SDK-Resolver "{0}" hat NULL zurückgegeben. + + SDK '{0}' could not be resolved by the SDK resolver '{1}'. {2} + SDK „{0}“ konnte vom SDK-Resolver „{1}“ nicht aufgelöst werden. {2} + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: Das Projekt "{0}" hat Graphisolationseinschränkungen für das referenzierte Projekt "{1}" übersprungen. diff --git a/src/msbuild/src/Build/Resources/xlf/Strings.es.xlf b/src/msbuild/src/Build/Resources/xlf/Strings.es.xlf index ecb3a3815d6..b4584d786bf 100644 --- a/src/msbuild/src/Build/Resources/xlf/Strings.es.xlf +++ b/src/msbuild/src/Build/Resources/xlf/Strings.es.xlf @@ -860,6 +860,11 @@ Errores: {3} La resolución del SDK "{0}" devolvió null. + + SDK '{0}' could not be resolved by the SDK resolver '{1}'. {2} + El SDK '{0}' no se pudo resolver mediante la resolución de SDK '{1}'. {2} + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: El proyecto "{0}" ha omitido las restricciones de aislamiento de gráficos en el proyecto "{1}" al que se hace referencia. diff --git a/src/msbuild/src/Build/Resources/xlf/Strings.fr.xlf b/src/msbuild/src/Build/Resources/xlf/Strings.fr.xlf index de96b1472c8..909a507f566 100644 --- a/src/msbuild/src/Build/Resources/xlf/Strings.fr.xlf +++ b/src/msbuild/src/Build/Resources/xlf/Strings.fr.xlf @@ -860,6 +860,11 @@ Erreurs : {3} Le programme de résolution du Kit de développement logiciel (SDK) «{0}» a retourné null. + + SDK '{0}' could not be resolved by the SDK resolver '{1}'. {2} + Le Kit de développement logiciel (SDK) « {0} » n’a pas pu être résolu par le résolveur de SDK « {1} ». {2} + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: le projet "{0}" a ignoré les contraintes d'isolement de graphe dans le projet référencé "{1}" diff --git a/src/msbuild/src/Build/Resources/xlf/Strings.it.xlf b/src/msbuild/src/Build/Resources/xlf/Strings.it.xlf index d4acfbaa817..44e0f02b051 100644 --- a/src/msbuild/src/Build/Resources/xlf/Strings.it.xlf +++ b/src/msbuild/src/Build/Resources/xlf/Strings.it.xlf @@ -860,6 +860,11 @@ Errori: {3} Il resolver SDK "{0}" ha restituito null. + + SDK '{0}' could not be resolved by the SDK resolver '{1}'. {2} + Il resolver SDK '{0}' non è riuscito a risolvere l'SDK '{1}'. {2} + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: il progetto "{0}" ha ignorato i vincoli di isolamento del grafico nel progetto di riferimento "{1}" diff --git a/src/msbuild/src/Build/Resources/xlf/Strings.ja.xlf b/src/msbuild/src/Build/Resources/xlf/Strings.ja.xlf index 8de15be3a29..fa181c689ea 100644 --- a/src/msbuild/src/Build/Resources/xlf/Strings.ja.xlf +++ b/src/msbuild/src/Build/Resources/xlf/Strings.ja.xlf @@ -860,6 +860,11 @@ Errors: {3} SDK リゾルバー "{0}" が null を返しました。 + + SDK '{0}' could not be resolved by the SDK resolver '{1}'. {2} + SDK '{0}' を SDK リゾルバー '{1}' で解決できませんでした。{2} + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: プロジェクト "{0}" は、参照先のプロジェクト "{1}" で、グラフの分離制約をスキップしました diff --git a/src/msbuild/src/Build/Resources/xlf/Strings.ko.xlf b/src/msbuild/src/Build/Resources/xlf/Strings.ko.xlf index 03bc234c5ef..f5766935dde 100644 --- a/src/msbuild/src/Build/Resources/xlf/Strings.ko.xlf +++ b/src/msbuild/src/Build/Resources/xlf/Strings.ko.xlf @@ -860,6 +860,11 @@ Errors: {3} SDK 확인자 "{0}"이(가) null을 반환했습니다. + + SDK '{0}' could not be resolved by the SDK resolver '{1}'. {2} + SDK 확인자 '{1}'에서 SDK '{0}'을(를) 확인할 수 없습니다. {2} + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: 프로젝트 "{0}"에서 참조된 프로젝트 "{1}"의 그래프 격리 제약 조건을 건너뛰었습니다. diff --git a/src/msbuild/src/Build/Resources/xlf/Strings.pl.xlf b/src/msbuild/src/Build/Resources/xlf/Strings.pl.xlf index 019d29d3fb0..a218f56d244 100644 --- a/src/msbuild/src/Build/Resources/xlf/Strings.pl.xlf +++ b/src/msbuild/src/Build/Resources/xlf/Strings.pl.xlf @@ -860,6 +860,11 @@ Błędy: {3} Narzędzie Resolver zestawu SDK „{0}” zwróciło wartość null. + + SDK '{0}' could not be resolved by the SDK resolver '{1}'. {2} + Nie można rozpoznać zestawu SDK „{0}” przez program rozpoznawania nazw zestawu SDK „{1}”. {2} + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: W przypadku projektu „{0}” pominięto ograniczenia izolacji grafu dla przywoływanego projektu „{1}” diff --git a/src/msbuild/src/Build/Resources/xlf/Strings.pt-BR.xlf b/src/msbuild/src/Build/Resources/xlf/Strings.pt-BR.xlf index f975fac9acb..bde8513a69a 100644 --- a/src/msbuild/src/Build/Resources/xlf/Strings.pt-BR.xlf +++ b/src/msbuild/src/Build/Resources/xlf/Strings.pt-BR.xlf @@ -860,6 +860,11 @@ Erros: {3} O resolvedor do SDK "{0}" retornou nulo. + + SDK '{0}' could not be resolved by the SDK resolver '{1}'. {2} + O SDK '{0}' não pôde ser resolvido pelo resolvedor de SDK '{1}'. {2} + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: o projeto "{0}" ignorou as restrições de isolamento do gráfico no projeto referenciado "{1}" diff --git a/src/msbuild/src/Build/Resources/xlf/Strings.ru.xlf b/src/msbuild/src/Build/Resources/xlf/Strings.ru.xlf index 83bbbb6e1d1..34b7d9d8b23 100644 --- a/src/msbuild/src/Build/Resources/xlf/Strings.ru.xlf +++ b/src/msbuild/src/Build/Resources/xlf/Strings.ru.xlf @@ -860,6 +860,11 @@ Errors: {3} Сопоставитель пакетов SDK "{0}" вернул значение null. + + SDK '{0}' could not be resolved by the SDK resolver '{1}'. {2} + Не удалось разрешить SDK "{0}" с помощью сопоставителя SDK "{1}". {2} + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: проект "{0}" пропустил ограничения изоляции графа в проекте "{1}", на который указывает ссылка. diff --git a/src/msbuild/src/Build/Resources/xlf/Strings.tr.xlf b/src/msbuild/src/Build/Resources/xlf/Strings.tr.xlf index 418670f2595..004fafbaa16 100644 --- a/src/msbuild/src/Build/Resources/xlf/Strings.tr.xlf +++ b/src/msbuild/src/Build/Resources/xlf/Strings.tr.xlf @@ -860,6 +860,11 @@ Hatalar: {3} SDK çözümleyici "{0}" null döndürdü. + + SDK '{0}' could not be resolved by the SDK resolver '{1}'. {2} + SDK '{0}', SDK çözümleyici '{1}' tarafından çözümlenemedi. {2} + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: "{0}" projesi, başvurulan "{1}" projesindeki graf yalıtımı kısıtlamalarını atladı diff --git a/src/msbuild/src/Build/Resources/xlf/Strings.zh-Hans.xlf b/src/msbuild/src/Build/Resources/xlf/Strings.zh-Hans.xlf index 46aef2401a8..13047d4ac40 100644 --- a/src/msbuild/src/Build/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/msbuild/src/Build/Resources/xlf/Strings.zh-Hans.xlf @@ -860,6 +860,11 @@ Errors: {3} SDK 解析程序“{0}”返回 null。 + + SDK '{0}' could not be resolved by the SDK resolver '{1}'. {2} + SDK 解析程序“{1}”无法解析 SDK“{0}”。{2} + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: 项目“{0}”已跳过所引用的项目“{1}”上的图形隔离约束 diff --git a/src/msbuild/src/Build/Resources/xlf/Strings.zh-Hant.xlf b/src/msbuild/src/Build/Resources/xlf/Strings.zh-Hant.xlf index 1b5d8c86b82..c4be1e9169a 100644 --- a/src/msbuild/src/Build/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/msbuild/src/Build/Resources/xlf/Strings.zh-Hant.xlf @@ -860,6 +860,11 @@ Errors: {3} SDK 解析程式 "{0}" 傳回 Null。 + + SDK '{0}' could not be resolved by the SDK resolver '{1}'. {2} + SDK 解析程式 '{1}' 無法解析 SDK '{0}'。{2} + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: 專案 "{0}" 已跳過參考專案 "{1}" 上的圖形隔離條件約束 diff --git a/src/msbuild/src/StringTools.UnitTests/WeakStringCache_Tests.cs b/src/msbuild/src/StringTools.UnitTests/WeakStringCache_Tests.cs index 95c769a5fa7..29e51267c1c 100644 --- a/src/msbuild/src/StringTools.UnitTests/WeakStringCache_Tests.cs +++ b/src/msbuild/src/StringTools.UnitTests/WeakStringCache_Tests.cs @@ -86,7 +86,7 @@ private void AddStringsWithSameHashCode(int numberOfStrings) for (int i = 0; i < numberOfStrings; i++) { - string strPart2 = string.Concat(Enumerable.Repeat("100570862200", i + 2)); + string strPart2 = string.Concat(Enumerable.Repeat("100570862200", i + 100)); hashCodes[i] = AddString(string.Empty, strPart2, (string cachedString) => { _cache.GetDebugInfo().ShouldBe(new WeakStringCache.DebugInfo() @@ -124,7 +124,7 @@ private void AddStringsWithSameHashCode(int numberOfStrings) public void RetainsStringUntilCollected() { // Add a string to the cache using a non-inlinable method to make sure it's not reachable from a GC root. - AddString("Random string ", "test", (string cachedString) => + AddString(new string('r', 500), "test", (string cachedString) => { _cache.GetDebugInfo().ShouldBe(new WeakStringCache.DebugInfo() { diff --git a/src/msbuild/src/StringTools/StringTools.cs b/src/msbuild/src/StringTools/StringTools.cs index 93b06619b5d..0ee22092369 100644 --- a/src/msbuild/src/StringTools/StringTools.cs +++ b/src/msbuild/src/StringTools/StringTools.cs @@ -92,6 +92,11 @@ public static string CreateDiagnosticReport() return WeakStringCacheInterner.Instance.FormatStatistics(); } + public static void ClearCachedStrings() + { + WeakStringCacheInterner.Instance.Dispose(); + } + #endregion /// diff --git a/src/msbuild/src/StringTools/WeakStringCache.cs b/src/msbuild/src/StringTools/WeakStringCache.cs index 5e3434fd4ef..5517e1478cc 100644 --- a/src/msbuild/src/StringTools/WeakStringCache.cs +++ b/src/msbuild/src/StringTools/WeakStringCache.cs @@ -35,10 +35,15 @@ private class StringWeakHandle /// public GCHandle WeakHandle; + /// + /// Reference used for smaller strings retained by the cache. + /// + private string? referencedString; + /// /// Returns true if the string referenced by the handle is still alive. /// - public bool IsUsed => WeakHandle.Target != null; + public bool IsUsed => referencedString is not null || WeakHandle.Target != null; /// /// Returns the string referenced by this handle if it is equal to the given internable. @@ -47,13 +52,26 @@ private class StringWeakHandle /// The string matching the internable or null if the handle is referencing a collected string or the string is different. public string? GetString(ref InternableString internable) { - if (WeakHandle.IsAllocated && WeakHandle.Target is string str) + if (referencedString is not null && internable.Equals(referencedString)) { - if (internable.Equals(str)) - { - return str; - } + return referencedString; + } + + if (!WeakHandle.IsAllocated) + { + return null; + } + + if (WeakHandle.Target is not string str) + { + return null; } + + if (internable.Equals(str)) + { + return str; + } + return null; } @@ -63,14 +81,28 @@ private class StringWeakHandle /// The string to set. public void SetString(string str) { - if (!WeakHandle.IsAllocated) + const int stringLengthLimit = 500; + if (str.Length > stringLengthLimit) { - // The handle is not allocated - allocate it. - WeakHandle = GCHandle.Alloc(str, GCHandleType.Weak); + if (WeakHandle.IsAllocated) + { + WeakHandle.Target = str; + } + else + { + WeakHandle = GCHandle.Alloc(str, GCHandleType.Weak); + } + + referencedString = null; } else { - WeakHandle.Target = str; + if (WeakHandle.IsAllocated) + { + WeakHandle.Target = null; + } + + referencedString = str; } } @@ -79,7 +111,10 @@ public void SetString(string str) /// public void Free() { - WeakHandle.Free(); + if (WeakHandle.IsAllocated) + { + WeakHandle.Free(); + } } } @@ -106,12 +141,6 @@ private void DisposeImpl() } public void Dispose() - { - DisposeImpl(); - GC.SuppressFinalize(this); - } - - ~WeakStringCache() { DisposeImpl(); } diff --git a/src/msbuild/src/Tasks/GenerateResource.cs b/src/msbuild/src/Tasks/GenerateResource.cs index 1726600bd8c..7c41f6fcbf3 100644 --- a/src/msbuild/src/Tasks/GenerateResource.cs +++ b/src/msbuild/src/Tasks/GenerateResource.cs @@ -16,6 +16,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; +using System.Linq; using System.Resources; using System.Resources.Extensions; using System.Reflection; @@ -41,7 +42,6 @@ using Microsoft.Build.Utilities; #if FEATURE_RESXREADER_LIVEDESERIALIZATION using Microsoft.Win32; -using System.Linq; #endif #nullable disable @@ -1705,7 +1705,7 @@ private void UpdateNewestUncorrelatedInputWriteTime() // Check the timestamp of each of the passed-in references to find the newest; // and then the additional inputs - ITaskItem[] inputs = this.References ?? [.. (this.AdditionalInputs ?? [])]; + var inputs = (this.References ?? []).Concat(this.AdditionalInputs ?? []); foreach (ITaskItem input in inputs) { diff --git a/src/msbuild/src/Tasks/Microsoft.CSharp.CurrentVersion.targets b/src/msbuild/src/Tasks/Microsoft.CSharp.CurrentVersion.targets index 0280966ef15..6e30cf7fba4 100644 --- a/src/msbuild/src/Tasks/Microsoft.CSharp.CurrentVersion.targets +++ b/src/msbuild/src/Tasks/Microsoft.CSharp.CurrentVersion.targets @@ -248,6 +248,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. ChecksumAlgorithm="$(ChecksumAlgorithm)" CodeAnalysisRuleSet="$(ResolvedCodeAnalysisRuleSet)" CodePage="$(CodePage)" + CompilerType="$(RoslynCompilerType)" DebugType="none" DefineConstants="$(DefineConstants)" DelaySign="$(DelaySign)" @@ -262,6 +263,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. ErrorLog="$(ErrorLog)" ErrorReport="$(ErrorReport)" Features="$(Features)" + InterceptorsNamespaces="$(InterceptorsNamespaces)" InterceptorsPreviewNamespaces="$(InterceptorsPreviewNamespaces)" FileAlignment="$(FileAlignment)" GeneratedFilesOutputPath="$(CompilerGeneratedFilesOutputPath)" diff --git a/src/msbuild/src/Tasks/Microsoft.VisualBasic.CurrentVersion.targets b/src/msbuild/src/Tasks/Microsoft.VisualBasic.CurrentVersion.targets index 73299be40f1..fe304b229f5 100644 --- a/src/msbuild/src/Tasks/Microsoft.VisualBasic.CurrentVersion.targets +++ b/src/msbuild/src/Tasks/Microsoft.VisualBasic.CurrentVersion.targets @@ -238,6 +238,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. ChecksumAlgorithm="$(ChecksumAlgorithm)" CodeAnalysisRuleSet="$(ResolvedCodeAnalysisRuleSet)" CodePage="$(CodePage)" + CompilerType="$(RoslynCompilerType)" DebugType="none" DefineConstants="$(FinalDefineConstants)" DelaySign="$(DelaySign)" diff --git a/src/nuget-client/.github/policies/prBuddyAssignment.yml b/src/nuget-client/.github/policies/prBuddyAssignment.yml new file mode 100644 index 00000000000..e669b54bcdb --- /dev/null +++ b/src/nuget-client/.github/policies/prBuddyAssignment.yml @@ -0,0 +1,89 @@ +name: PR Buddy Assignment +description: Automatically Assign pr Buddies. +owner: +resource: repository +disabled: false +where: +configuration: + resourceManagementConfiguration: + eventResponderTasks: + - if: + - payloadType: Pull_Request + - isAction: + action: Opened + then: + - if: + - isActivitySender: + user: jgonz120 + then: + - assignTo: + user: nkolev92 + - assignTo: + user: martinrrm + - if: + - isActivitySender: + user: nkolev92 + then: + - assignTo: + user: jgonz120 + - assignTo: + user: martinrrm + - if: + - isActivitySender: + user: martinrrm + then: + - assignTo: + user: jgonz120 + - assignTo: + user: nkolev92 + - if: + - isActivitySender: + user: zivkan + then: + - assignTo: + user: donnie-msft + - assignTo: + user: jeffkl + - if: + - isActivitySender: + user: donnie-msft + then: + - assignTo: + user: zivkan + - assignTo: + user: jeffkl + - if: + - isActivitySender: + user: jeffkl + then: + - assignTo: + user: zivkan + - assignTo: + user: donnie-msft + - if: + - isActivitySender: + user: jebriede + then: + - assignTo: + user: Nigusu-Allehu + - assignTo: + user: dtivel + - if: + - isActivitySender: + user: Nigusu-Allehu + then: + - assignTo: + user: jebriede + - assignTo: + user: dtivel + - if: + - isActivitySender: + user: dtivel + then: + - assignTo: + user: jebriede + - assignTo: + user: Nigusu-Allehu + description: Automatically Assign pr Buddies. +onFailure: +onSuccess: diff --git a/src/nuget-client/eng/DotNetBuild.props b/src/nuget-client/eng/DotNetBuild.props deleted file mode 100644 index 6d3a692356d..00000000000 --- a/src/nuget-client/eng/DotNetBuild.props +++ /dev/null @@ -1,14 +0,0 @@ - - - - - nuget-client - true - 1.0.0 - - - - true - - - diff --git a/src/nuget-client/eng/dotnet-build/build.ps1 b/src/nuget-client/eng/dotnet-build/build.ps1 index ee845b44586..9b76bbc201c 100644 --- a/src/nuget-client/eng/dotnet-build/build.ps1 +++ b/src/nuget-client/eng/dotnet-build/build.ps1 @@ -45,9 +45,9 @@ function Exec-Process([string]$command, [string]$commandArgs) { $dotnet = Join-Path $env:DOTNET_PATH dotnet.exe $repoRoot = Resolve-Path "$PSScriptRoot/../../" -$binLog = Join-Path $repoRoot "artifacts/sb/log/source-inner-build.binlog" +$binLog = Join-Path $repoRoot "artifacts/log/$configuration/Build.binlog" $dotnetTool = "msbuild" -$nugetPackagesRoot = Join-Path $repoRoot "artifacts/sb/package-cache/" +$nugetPackagesRoot = Join-Path $repoRoot "artifacts/.packages/" $dotnetArguments = @() # Environment variables diff --git a/src/nuget-client/eng/dotnet-build/build.sh b/src/nuget-client/eng/dotnet-build/build.sh index 908ebd5b70a..6f3a15bfd9f 100755 --- a/src/nuget-client/eng/dotnet-build/build.sh +++ b/src/nuget-client/eng/dotnet-build/build.sh @@ -86,7 +86,7 @@ fi ReadGlobalVersion Microsoft.DotNet.Arcade.Sdk export ARCADE_VERSION=$_ReadGlobalVersion -export NUGET_PACKAGES=${repo_root}artifacts/sb/package-cache/ +export NUGET_PACKAGES=${repo_root}artifacts/.packages/ if [[ "$source_build" == true ]]; then properties="$properties /p:DotNetBuildSourceOnly=true" @@ -96,4 +96,4 @@ properties="$properties /p:Configuration=$configuration" properties="$properties /p:DotNetBuildRepo=true" properties="$properties /p:RepoRoot=$repo_root" -"$DOTNET" msbuild -v:$verbosity "$scriptroot/dotnet-build.proj" "/bl:${repo_root}artifacts/sb/log/source-inner-build.binlog" $properties $args +"$DOTNET" msbuild -v:$verbosity "$scriptroot/dotnet-build.proj" "/bl:${repo_root}artifacts/log/${configuration}/Build.binlog" $properties $args diff --git a/src/nuget-client/eng/dotnet-build/dotnet-build.proj b/src/nuget-client/eng/dotnet-build/dotnet-build.proj index b1eca276cd0..2d2f7bd6fa0 100644 --- a/src/nuget-client/eng/dotnet-build/dotnet-build.proj +++ b/src/nuget-client/eng/dotnet-build/dotnet-build.proj @@ -1,60 +1,45 @@ - - $(MSBuildThisFileDirectory)../../ $(SOURCE_BUILT_SDK_DIR_ARCADE)/tools/ $(NuGetPackageRoot)/microsoft.dotnet.arcade.sdk/$(ARCADE_VERSION)/tools/ + true + 1.0.0 - <_CommonProperties Include="Configuration=$(Configuration)" /> <_CommonProperties Include="DotNetBuildOrchestrator=$(DotNetBuildOrchestrator)" Condition="'$(DotNetBuildOrchestrator)' != ''" /> <_CommonProperties Include="DotNetBuildRepo=true" /> <_CommonProperties Include="DotNetBuildSourceOnly=$(DotNetBuildSourceOnly)" Condition="'$(DotNetBuildSourceOnly)' != ''" /> - - - - - <_OuterBuildProperties Include="DotNetBuildPhase=Repo" /> - <_OuterBuildProperties Include="PreventPrebuiltBuild=false" /> - <_OuterBuildProperties Include="BaseInnerSourceBuildCommand=echo skipping inner sb invocation" /> - - - - <_InnerBuildProperties Include="DotNetBuildPhase=InnerRepo" /> - <_InnerBuildProperties Include="DotNetBuildInnerRepo=true" /> - <_InnerBuildProperties Condition="'$(VersionSuffixBuildOfTheDay)' != ''" Include="BuildNumber=$(VersionSuffixBuildOfTheDay)" /> + <_CommonProperties Include="BuildNumber=$(VersionSuffixBuildOfTheDay)" Condition="'$(VersionSuffixBuildOfTheDay)' != ''" /> - + - <_PublishProperties Include="DotNetPublishUsingPipelines=true" /> <_PublishProperties Include="PublishToSymbolServer=false" /> <_PublishProperties Include="AssetsLocalStorageDir=$(SourceBuiltAssetsDir)" /> <_PublishProperties Include="ShippingPackagesLocalStorageDir=$(SourceBuiltShippingPackagesDir)" /> @@ -62,17 +47,10 @@ <_PublishProperties Include="AssetManifestsLocalStorageDir=$(SourceBuiltAssetManifestsDir)" /> - - - - - diff --git a/src/nuget-client/src/NuGet.Clients/NuGet.CommandLine/Commands/ProjectFactory.cs b/src/nuget-client/src/NuGet.Clients/NuGet.CommandLine/Commands/ProjectFactory.cs index 804f530fc27..b97b1f70dc6 100644 --- a/src/nuget-client/src/NuGet.Clients/NuGet.CommandLine/Commands/ProjectFactory.cs +++ b/src/nuget-client/src/NuGet.Clients/NuGet.CommandLine/Commands/ProjectFactory.cs @@ -29,7 +29,6 @@ namespace NuGet.CommandLine { public class ProjectFactory : IProjectFactory, CoreV2.NuGet.IPropertyProvider, IDisposable { - private const string NUGET_ENABLE_LEGACY_PROJECT_JSON_PACK = nameof(NUGET_ENABLE_LEGACY_PROJECT_JSON_PACK); private const string NUGET_ENABLE_LEGACY_CSPROJ_PACK = nameof(NUGET_ENABLE_LEGACY_CSPROJ_PACK); // Its type is Microsoft.Build.Evaluation.Project @@ -37,8 +36,6 @@ public class ProjectFactory : IProjectFactory, CoreV2.NuGet.IPropertyProvider, I private ILogger _logger; - private bool _usingJsonFile; - private IEnvironmentVariableReader _environmentVariableReader; // Files we want to always exclude from the resulting package @@ -289,36 +286,8 @@ public PackageBuilder CreateBuilder(string basePath, NuGetVersion version, strin } } - Manifest manifest = null; - - // If there is a project.json file, load that and skip any nuspec that may exist -#pragma warning disable CS0612 // Type or member is obsolete - if (!PackCommandRunner.ProcessProjectJsonFile(builder, _project.DirectoryPath as string, builder.Id, version, suffix, GetPropertyValue)) -#pragma warning restore CS0612 // Type or member is obsolete - { - // If the package contains a nuspec file then use it for metadata - manifest = ProcessNuspec(builder, basePath); - } - else - { - Logger.Log( - PackagingLogMessage.CreateWarning( - string.Format(CultureInfo.CurrentCulture, NuGetResources.ProjectJsonPack_Deprecated, builder.Id), - NuGetLogCode.NU5126)); - _usingJsonFile = true; - - _ = bool.TryParse(_environmentVariableReader.GetEnvironmentVariable(NUGET_ENABLE_LEGACY_PROJECT_JSON_PACK), out bool enableLegacyProjectJsonPack); - - if (!enableLegacyProjectJsonPack) - { - Logger.Log( - PackagingLogMessage.CreateError( - string.Format(CultureInfo.CurrentCulture, NuGetResources.Error_ProjectJson_Deprecated_And_Removed, builder.Id, NUGET_ENABLE_LEGACY_PROJECT_JSON_PACK), - NuGetLogCode.NU5042)); - return null; - } - - } + // If the package contains a nuspec file then use it for metadata + Manifest manifest = ProcessNuspec(builder, basePath); // Remove the extra author if (builder.Authors.Count > 1) @@ -723,12 +692,6 @@ private void AddProjectReferenceDependencies(Dictionary dependencies) @@ -740,25 +703,11 @@ private PackageDependency CreateDependencyFromProject(dynamic project, Dictionar projectFactory.ProjectProperties = ProjectProperties; projectFactory.SymbolPackageFormat = SymbolPackageFormat; projectFactory.BuildProject(); - var builder = new Packaging.PackageBuilder(); + var builder = new PackageBuilder(); projectFactory.ExtractMetadata(builder); - projectFactory.InitializeProperties(builder); - -#pragma warning disable CS0612 // Type or member is obsolete - if (!projectFactory.ProcessJsonFile(builder, project.DirectoryPath, null)) -#pragma warning restore CS0612 // Type or member is obsolete - { - projectFactory.ProcessNuspec(builder, null); - } - else - { - Logger.Log( - PackagingLogMessage.CreateWarning( - string.Format(CultureInfo.CurrentCulture, NuGetResources.ProjectJsonPack_Deprecated, builder.Id), - NuGetLogCode.NU5126)); - } + projectFactory.ProcessNuspec(builder, null); VersionRange versionRange = null; if (dependencies.TryGetValue(builder.Id, out PackageDependency dependency)) @@ -824,22 +773,7 @@ private void ExtractMetadata(Packaging.PackageBuilder builder) private void AddOutputFiles(Packaging.PackageBuilder builder) { // Get the target framework of the project - NuGetFramework nugetFramework; - if (_usingJsonFile && builder.TargetFrameworks.Any()) - { - if (builder.TargetFrameworks.Count > 1) - { - var message = string.Format( - CultureInfo.CurrentCulture, - LocalizedResourceManager.GetString("Error_MultipleTargetFrameworks")); - throw new PackagingException(NuGetLogCode.NU5015, message); - } - nugetFramework = builder.TargetFrameworks.First(); - } - else - { - nugetFramework = TargetFramework; - } + NuGetFramework nugetFramework = TargetFramework; var projectOutputDirectory = Path.GetDirectoryName(TargetPath); string targetFileName; @@ -922,12 +856,10 @@ private void ProcessDependencies(Packaging.PackageBuilder builder) // Add the transform file to the package builder ProcessTransformFiles(builder, packages.SelectMany(GetTransformFiles)); - var dependencies = new Dictionary(); - if (!_usingJsonFile) - { - dependencies = builder.DependencyGroups.SelectMany(d => d.Packages) + var dependencies = new Dictionary(); + dependencies = builder.DependencyGroups.SelectMany(d => d.Packages) .ToDictionary(d => d.Id, StringComparer.OrdinalIgnoreCase); - } + // Reduce the set of packages we want to include as dependencies to the minimal set. // Normally, packages.config has the full closure included, we only add top level @@ -951,45 +883,11 @@ private void ProcessDependencies(Packaging.PackageBuilder builder) AddProjectReferenceDependencies(dependencies); } - if (_usingJsonFile) - { - if (dependencies.Any()) - { - if (builder.DependencyGroups.Any()) - { - var i = 0; - foreach (var group in builder.DependencyGroups.ToList()) - { - ISet newPackagesList = new HashSet(group.Packages); - foreach (var dependency in dependencies) - { - if (!newPackagesList.Contains(dependency.Value)) - { - newPackagesList.Add(dependency.Value); - } - } - - var dependencyGroup = new PackageDependencyGroup(group.TargetFramework, newPackagesList); + builder.DependencyGroups.Clear(); - builder.DependencyGroups.RemoveAt(i); - builder.DependencyGroups.Insert(i, dependencyGroup); + var targetFramework = TargetFramework ?? NuGetFramework.AnyFramework; + builder.DependencyGroups.Add(new PackageDependencyGroup(targetFramework, new HashSet(dependencies.Values))); - i++; - } - } - else - { - builder.DependencyGroups.Add(new PackageDependencyGroup(NuGetFramework.AnyFramework, new HashSet(dependencies.Values))); - } - } - } - else - { - builder.DependencyGroups.Clear(); - - var targetFramework = TargetFramework ?? NuGetFramework.AnyFramework; - builder.DependencyGroups.Add(new PackageDependencyGroup(targetFramework, new HashSet(dependencies.Values))); - } } private bool FindDependency(PackageIdentity projectPackage, IEnumerable> packagesAndDependencies) diff --git a/src/nuget-client/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Services/NuGetProjectManagerService.cs b/src/nuget-client/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Services/NuGetProjectManagerService.cs index f44435d45d8..48c7386a384 100644 --- a/src/nuget-client/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Services/NuGetProjectManagerService.cs +++ b/src/nuget-client/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Services/NuGetProjectManagerService.cs @@ -13,7 +13,6 @@ using Microsoft.ServiceHub.Framework; using Microsoft.ServiceHub.Framework.Services; using Microsoft.VisualStudio.Threading; -using NuGet.Common; using NuGet.Frameworks; using NuGet.PackageManagement.Telemetry; using NuGet.Packaging; @@ -26,6 +25,7 @@ using NuGet.Versioning; using NuGet.VisualStudio; using NuGet.VisualStudio.Internal.Contracts; +using NuGet.VisualStudio.Telemetry; using StreamJsonRpc; namespace NuGet.PackageManagement.VisualStudio @@ -38,23 +38,27 @@ public sealed class NuGetProjectManagerService : INuGetProjectManagerService private readonly INuGetProjectManagerServiceState _state; private readonly ISharedServiceState _sharedState; private AsyncSemaphore.Releaser? _semaphoreReleaser; + private readonly INuGetTelemetryProvider _telemetryProvider; public NuGetProjectManagerService( ServiceActivationOptions options, IServiceBroker serviceBroker, AuthorizationServiceClient authorizationServiceClient, + INuGetTelemetryProvider telemetryProvider, INuGetProjectManagerServiceState state, ISharedServiceState sharedServiceState) { Assumes.NotNull(serviceBroker); Assumes.NotNull(authorizationServiceClient); Assumes.NotNull(state); + Assumes.NotNull(telemetryProvider); Assumes.NotNull(sharedServiceState); _options = options; _serviceBroker = serviceBroker; _authorizationServiceClient = authorizationServiceClient; _state = state; + _telemetryProvider = telemetryProvider; _sharedState = sharedServiceState; } @@ -155,7 +159,7 @@ public async ValueTask> GetIns if (telemetryEvent is object) { - TelemetryActivity.EmitTelemetryEvent(telemetryEvent); + _telemetryProvider.EmitEvent(telemetryEvent); } return installedPackages; diff --git a/src/nuget-client/src/NuGet.Clients/NuGet.SolutionRestoreManager/RestoreManagerPackage.cs b/src/nuget-client/src/NuGet.Clients/NuGet.SolutionRestoreManager/RestoreManagerPackage.cs index babc7990a85..1a265d251fa 100644 --- a/src/nuget-client/src/NuGet.Clients/NuGet.SolutionRestoreManager/RestoreManagerPackage.cs +++ b/src/nuget-client/src/NuGet.Clients/NuGet.SolutionRestoreManager/RestoreManagerPackage.cs @@ -6,7 +6,7 @@ using System.Threading; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; -using NuGet.VisualStudio; +using NuGet.VisualStudio.Telemetry; using IBrokeredServiceContainer = Microsoft.VisualStudio.Shell.ServiceBroker.IBrokeredServiceContainer; // Duplicate type declarations due to Microsoft.Internal.VisualStudio.Shell.Embeddable. using ProvideBrokeredServiceAttribute = Microsoft.VisualStudio.Shell.ServiceBroker.ProvideBrokeredServiceAttribute; diff --git a/src/nuget-client/src/NuGet.Clients/NuGet.SolutionRestoreManager/SolutionRestoreJob.cs b/src/nuget-client/src/NuGet.Clients/NuGet.SolutionRestoreManager/SolutionRestoreJob.cs index e4ea44cf96e..1bf8b0c4838 100644 --- a/src/nuget-client/src/NuGet.Clients/NuGet.SolutionRestoreManager/SolutionRestoreJob.cs +++ b/src/nuget-client/src/NuGet.Clients/NuGet.SolutionRestoreManager/SolutionRestoreJob.cs @@ -51,6 +51,7 @@ internal sealed class SolutionRestoreJob : ISolutionRestoreJob private readonly ISolutionRestoreChecker _solutionUpToDateChecker; private readonly IVsNuGetProgressReporter _nuGetProgressReporter; private readonly IAuditCheckResultCachingService _auditResultCachingService; + private readonly INuGetTelemetryProvider _nuGetTelemetryProvider; private RestoreOperationLogger _logger; private INuGetProjectContext _nuGetProjectContext; @@ -83,7 +84,8 @@ public SolutionRestoreJob( ISettings settings, ISolutionRestoreChecker solutionRestoreChecker, IVsNuGetProgressReporter nuGetProgressReporter, - IAuditCheckResultCachingService auditResultCachingService) + IAuditCheckResultCachingService auditResultCachingService, + INuGetTelemetryProvider nuGetTelemetryProvider) : this(AsyncServiceProvider.GlobalProvider, packageRestoreManager, solutionManager, @@ -92,9 +94,11 @@ public SolutionRestoreJob( settings, solutionRestoreChecker, nuGetProgressReporter, - auditResultCachingService + auditResultCachingService, + nuGetTelemetryProvider ) - { } + { + } public SolutionRestoreJob( IAsyncServiceProvider asyncServiceProvider, @@ -105,7 +109,8 @@ public SolutionRestoreJob( ISettings settings, ISolutionRestoreChecker solutionRestoreChecker, IVsNuGetProgressReporter nuGetProgressReporter, - IAuditCheckResultCachingService auditResultCachingService) + IAuditCheckResultCachingService auditResultCachingService, + INuGetTelemetryProvider nuGetTelemetryProvider) { Assumes.Present(asyncServiceProvider); Assumes.Present(packageRestoreManager); @@ -116,6 +121,7 @@ public SolutionRestoreJob( Assumes.Present(solutionRestoreChecker); Assumes.Present(nuGetProgressReporter); Assumes.Present(auditResultCachingService); + Assumes.Present(nuGetTelemetryProvider); _asyncServiceProvider = asyncServiceProvider; _packageRestoreManager = packageRestoreManager; @@ -127,6 +133,8 @@ public SolutionRestoreJob( _solutionUpToDateChecker = solutionRestoreChecker; _nuGetProgressReporter = nuGetProgressReporter; _auditResultCachingService = auditResultCachingService; + _nuGetTelemetryProvider = nuGetTelemetryProvider; + } @@ -388,11 +396,11 @@ private void EmitRestoreTelemetryEvent(IEnumerable projects, hasVSOfflineFeed); _auditResultCachingService.LastAuditCheckResult?.AddMetricsToTelemetry(restoreTelemetryEvent); - TelemetryActivity.EmitTelemetryEvent(restoreTelemetryEvent); + _nuGetTelemetryProvider.EmitEvent(restoreTelemetryEvent); var sourceEvent = SourceTelemetry.GetRestoreSourceSummaryEvent(_nuGetProjectContext.OperationId, packageSources, protocolDiagnosticTotals); - TelemetryActivity.EmitTelemetryEvent(sourceEvent); + _nuGetTelemetryProvider.EmitEvent(sourceEvent); } private async Task RestorePackageSpecProjectsAsync( diff --git a/src/nuget-client/src/NuGet.Clients/NuGet.Tools/NuGetBrokeredServiceFactory.cs b/src/nuget-client/src/NuGet.Clients/NuGet.Tools/NuGetBrokeredServiceFactory.cs index d1daafcc1a3..a9512e86ddf 100644 --- a/src/nuget-client/src/NuGet.Clients/NuGet.Tools/NuGetBrokeredServiceFactory.cs +++ b/src/nuget-client/src/NuGet.Clients/NuGet.Tools/NuGetBrokeredServiceFactory.cs @@ -111,11 +111,14 @@ private async ValueTask CreateProjectManagerServiceAsync( { await _lazyInitializer.InitializeAsync(cancellationToken); + INuGetTelemetryProvider telemetryProvider = await _lazyTelemetryProvider.GetValueAsync(cancellationToken); + #pragma warning disable CA2000 // Dispose objects before losing scope var service = new NuGetProjectManagerService( options, serviceBroker, authorizationServiceClient, + telemetryProvider, _projectManagerServiceSharedState, _sharedServiceState); #pragma warning restore CA2000 // Dispose objects before losing scope diff --git a/src/nuget-client/src/NuGet.Clients/NuGet.Tools/NuGetPackage.cs b/src/nuget-client/src/NuGet.Clients/NuGet.Tools/NuGetPackage.cs index 560c9da2bde..b03b5affb9d 100644 --- a/src/nuget-client/src/NuGet.Clients/NuGet.Tools/NuGetPackage.cs +++ b/src/nuget-client/src/NuGet.Clients/NuGet.Tools/NuGetPackage.cs @@ -55,9 +55,7 @@ namespace NuGetVSExtension Window = "{34E76E81-EE4A-11D0-AE2E-00A0C90FFFC3}", // this is the guid of the Output tool window, which is present in both VS and VWD Orientation = ToolWindowOrientation.Right)] [ProvideOptionPage(typeof(GeneralOptionPage), "NuGet Package Manager", "General", 113, 115, true, IsInUnifiedSettings = true)] - [ProvideOptionPage(typeof(StubGeneralOptionsPage), "NuGet Package Manager", "GeneralStub", 113, 115, true, IsInUnifiedSettings = false, Sort = 0, - // Only show the stub legacy settings General page by using a visibility context indicating when the unified settings feature is enabled. - VisibilityCmdUIContexts = "13b56f17-0b98-4a51-a9a0-9767d84796da")] + [ProvideOptionPage(typeof(StubGeneralOptionsPage), "NuGet Package Manager", "GeneralStub", 113, 115, true, IsInUnifiedSettings = false, Sort = 0)] [ProvideOptionPage(typeof(ConfigurationFilesOptionsPage), "NuGet Package Manager", "Configuration Files", 113, 117, true, IsInUnifiedSettings = true, Sort = 1)] [ProvideOptionPage(typeof(PackageSourceOptionsPage), "NuGet Package Manager", "Package Sources", 113, 114, true, Sort = 2)] [ProvideOptionPage(typeof(PackageSourceMappingOptionsPage), "NuGet Package Manager", "Package Source Mapping", 113, 116, true, Sort = 3)] @@ -166,7 +164,7 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke { NuGetVSTelemetryService.Initialize(); - _nuGetPowerShellUsageCollector = new NuGetPowerShellUsageCollector(); + _nuGetPowerShellUsageCollector = new NuGetPowerShellUsageCollector(NuGet.Common.TelemetryActivity.NuGetTelemetryService); await base.InitializeAsync(cancellationToken, progress); // Add our command handlers for menu (commands must exist in the .vsct file) diff --git a/src/nuget-client/src/NuGet.Clients/NuGet.VisualStudio.Common/Telemetry/NuGetPowerShellUsageCollector.cs b/src/nuget-client/src/NuGet.Clients/NuGet.VisualStudio.Common/Telemetry/NuGetPowerShellUsageCollector.cs index bb537ebc122..590d8373943 100644 --- a/src/nuget-client/src/NuGet.Clients/NuGet.VisualStudio.Common/Telemetry/NuGetPowerShellUsageCollector.cs +++ b/src/nuget-client/src/NuGet.Clients/NuGet.VisualStudio.Common/Telemetry/NuGetPowerShellUsageCollector.cs @@ -45,8 +45,11 @@ public sealed class NuGetPowerShellUsageCollector : IDisposable private readonly InstanceData _vsInstanceData; private object _lock = new object(); - public NuGetPowerShellUsageCollector() + private readonly INuGetTelemetryService _nuGetTelemetryService; + + public NuGetPowerShellUsageCollector(INuGetTelemetryService nuGetTelemetryService) { + _nuGetTelemetryService = nuGetTelemetryService ?? throw new ArgumentNullException(nameof(nuGetTelemetryService)); _vsSolutionData = new SolutionData(); _vsInstanceData = new InstanceData(); @@ -202,7 +205,7 @@ private void NuGetPowerShellUsage_SolutionOpenHandler() if (!_vsSolutionData.SolutionLoaded && _vsSolutionData.PmcExecuteCommandCount > 0) { // PMC used before any solution is loaded, let's emit what we have for nugetvsinstanceclose event. - TelemetryActivity.EmitTelemetryEvent(_vsSolutionData.ToTelemetryEvent()); + _nuGetTelemetryService.EmitTelemetryEvent(_vsSolutionData.ToTelemetryEvent()); ClearSolutionData(); } @@ -225,7 +228,7 @@ private void NuGetPowerShellUsage_SolutionCloseHandler() { lock (_lock) { - TelemetryActivity.EmitTelemetryEvent(_vsSolutionData.ToTelemetryEvent()); + _nuGetTelemetryService.EmitTelemetryEvent(_vsSolutionData.ToTelemetryEvent()); ClearSolutionData(); } } @@ -238,7 +241,7 @@ private void NuGetPowerShellUsage_VSInstanseCloseHandler(object sender, Telemetr if (!_vsSolutionData.SolutionLoaded && _vsSolutionData.PmcExecuteCommandCount > 0) { // PMC used before any solution is loaded, let's emit what we have for nugetvsinstanceclose event. - TelemetryActivity.EmitTelemetryEvent(_vsSolutionData.ToTelemetryEvent()); + _nuGetTelemetryService.EmitTelemetryEvent(_vsSolutionData.ToTelemetryEvent()); } // Add VS Instance telemetry diff --git a/src/nuget-client/src/NuGet.Clients/NuGet.VisualStudio.Common/Telemetry/NuGetTelemetryProvider.cs b/src/nuget-client/src/NuGet.Clients/NuGet.VisualStudio.Common/Telemetry/NuGetTelemetryProvider.cs index 3b4fc8471c8..156269ebdd0 100644 --- a/src/nuget-client/src/NuGet.Clients/NuGet.VisualStudio.Common/Telemetry/NuGetTelemetryProvider.cs +++ b/src/nuget-client/src/NuGet.Clients/NuGet.VisualStudio.Common/Telemetry/NuGetTelemetryProvider.cs @@ -14,7 +14,7 @@ namespace NuGet.VisualStudio.Telemetry [Export(typeof(INuGetTelemetryProvider))] internal sealed class NuGetTelemetryProvider : INuGetTelemetryProvider, IDisposable { - ExtensibilityTelemetryCollector _extensibilityTelemetryCollector; + private ExtensibilityTelemetryCollector _extensibilityTelemetryCollector; public NuGetTelemetryProvider() { diff --git a/src/nuget-client/src/NuGet.Clients/NuGet.VisualStudio.Common/Telemetry/NuGetVSActionTelemetryService.cs b/src/nuget-client/src/NuGet.Clients/NuGet.VisualStudio.Common/Telemetry/NuGetVSTelemetryService.cs similarity index 95% rename from src/nuget-client/src/NuGet.Clients/NuGet.VisualStudio.Common/Telemetry/NuGetVSActionTelemetryService.cs rename to src/nuget-client/src/NuGet.Clients/NuGet.VisualStudio.Common/Telemetry/NuGetVSTelemetryService.cs index 52f1ad2abb3..b32c97f6729 100644 --- a/src/nuget-client/src/NuGet.Clients/NuGet.VisualStudio.Common/Telemetry/NuGetVSActionTelemetryService.cs +++ b/src/nuget-client/src/NuGet.Clients/NuGet.VisualStudio.Common/Telemetry/NuGetVSTelemetryService.cs @@ -3,9 +3,8 @@ using System; using NuGet.Common; -using NuGet.VisualStudio.Telemetry; -namespace NuGet.VisualStudio +namespace NuGet.VisualStudio.Telemetry { /// /// Telemetry service class for restore operation diff --git a/src/nuget-client/src/NuGet.Clients/NuGet.VisualStudio.OnlineEnvironment.Client/NuGetClientPackage.cs b/src/nuget-client/src/NuGet.Clients/NuGet.VisualStudio.OnlineEnvironment.Client/NuGetClientPackage.cs index 12cfc0f54cd..a1084fdc07f 100644 --- a/src/nuget-client/src/NuGet.Clients/NuGet.VisualStudio.OnlineEnvironment.Client/NuGetClientPackage.cs +++ b/src/nuget-client/src/NuGet.Clients/NuGet.VisualStudio.OnlineEnvironment.Client/NuGetClientPackage.cs @@ -3,6 +3,7 @@ using System.Threading; using Microsoft.VisualStudio.Shell; using NuGet.PackageManagement.UI; +using NuGet.VisualStudio.Telemetry; using Task = System.Threading.Tasks.Task; namespace NuGet.VisualStudio.OnlineEnvironment.Client diff --git a/src/nuget-client/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageReferenceCommands/ListPackage/ListPackageCommandRunner.cs b/src/nuget-client/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageReferenceCommands/ListPackage/ListPackageCommandRunner.cs index d49af9b30d1..03d9296b8b7 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageReferenceCommands/ListPackage/ListPackageCommandRunner.cs +++ b/src/nuget-client/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageReferenceCommands/ListPackage/ListPackageCommandRunner.cs @@ -127,7 +127,14 @@ private async Task GetProjectMetadataAsync( if (listPackageArgs.ReportType != ReportType.Default) // generic list package is offline -- no server lookups { - WarnForHttpSources(listPackageArgs, projectModel); + List httpSources = HttpSourcesUtility.GetDisallowedInsecureHttpSources(listPackageArgs.PackageSources); + httpSources.AddRange(HttpSourcesUtility.GetDisallowedInsecureHttpSources(listPackageArgs.AuditSources)); + + if (httpSources.Count > 0) + { + projectModel.AddProjectInformation(ProblemType.Error, HttpSourcesUtility.BuildHttpSourceErrorMessage(httpSources, "list package")); + return; + } if (listPackageArgs.ReportType == ReportType.Vulnerable && listPackageArgs.AuditSources != null && listPackageArgs.AuditSources.Count > 0) { @@ -325,43 +332,6 @@ private static IEnumerable GetPackageVulnerabiliti return Enumerable.Empty(); } - private static void WarnForHttpSources( - ListPackageArgs listPackageArgs, - ListPackageProjectModel projectModel) - { - var httpPackageSources = new List(); - - AddHttpPackageSources(listPackageArgs.PackageSources, httpPackageSources); - AddHttpPackageSources(listPackageArgs.AuditSources, httpPackageSources); - - if (httpPackageSources.Count == 0) - { - return; - } - - string warningMessage = httpPackageSources.Count == 1 - ? string.Format(CultureInfo.CurrentCulture, Strings.Warning_HttpServerUsage, "list package", httpPackageSources[0]) - : string.Format(CultureInfo.CurrentCulture, Strings.Warning_HttpServerUsage_MultipleSources, "list package", Environment.NewLine + string.Join(Environment.NewLine, httpPackageSources.Select(e => e.Name))); - - projectModel.AddProjectInformation(ProblemType.Warning, warningMessage); - } - - private static void AddHttpPackageSources(IEnumerable packageSources, List httpPackageSources) - { - if (packageSources == null) - { - return; - } - - foreach (var packageSource in packageSources) - { - if (packageSource.IsHttp && !packageSource.IsHttps && !packageSource.AllowInsecureConnections) - { - httpPackageSources.Add(packageSource); - } - } - } - public static bool FilterPackages(IEnumerable packages, ListPackageArgs listPackageArgs) { switch (listPackageArgs.ReportType) diff --git a/src/nuget-client/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageSearch/PackageSearchRunner.cs b/src/nuget-client/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageSearch/PackageSearchRunner.cs index 6efb73fc252..6e4218a33f9 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageSearch/PackageSearchRunner.cs +++ b/src/nuget-client/src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageSearch/PackageSearchRunner.cs @@ -3,10 +3,10 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; +using NuGet.CommandLine.XPlat.Utility; using NuGet.Commands; using NuGet.Common; using NuGet.Configuration; @@ -55,7 +55,14 @@ public static async Task RunAsync( return ExitCodes.Error; } - WarnForHTTPSources(listEndpoints, packageSearchArgs.Logger); + List httpSources = HttpSourcesUtility.GetDisallowedInsecureHttpSources(listEndpoints.ToList()); + + if (httpSources.Count > 0) + { + packageSearchResultRenderer.Add(new PackageSearchProblem(PackageSearchProblemType.Error, HttpSourcesUtility.BuildHttpSourceErrorMessage(httpSources, "search"))); + packageSearchResultRenderer.Finish(); + return ExitCodes.Error; + } if (listEndpoints == null || listEndpoints.Count == 0) { @@ -218,49 +225,5 @@ private static IList GetPackageSources(List sources, IPac return packageSources.ToList(); } - - /// - /// Warns the user if the provided package sources use insecure HTTP connections. - /// - /// The list of package sources to check. - /// The logger instance to use for logging. - private static void WarnForHTTPSources(IList packageSources, ILogger logger) - { - List httpPackageSources = null; - - foreach (PackageSource packageSource in packageSources) - { - if (packageSource.IsHttp && !packageSource.IsHttps && !packageSource.AllowInsecureConnections) - { - if (httpPackageSources == null) - { - httpPackageSources = new(capacity: packageSources.Count); - } - httpPackageSources.Add(packageSource); - } - } - - if (httpPackageSources != null && httpPackageSources.Count != 0) - { - if (httpPackageSources.Count == 1) - { - logger.LogWarning( - string.Format( - CultureInfo.CurrentCulture, - Strings.Warning_HttpServerUsage, - "search", - httpPackageSources[0])); - } - else - { - logger.LogWarning( - string.Format( - CultureInfo.CurrentCulture, - Strings.Warning_HttpServerUsage_MultipleSources, - "search", - Environment.NewLine + string.Join(Environment.NewLine, httpPackageSources.Select(e => e.Name)))); - } - } - } } } diff --git a/src/nuget-client/src/NuGet.Core/NuGet.CommandLine.XPlat/Strings.Designer.cs b/src/nuget-client/src/NuGet.Core/NuGet.CommandLine.XPlat/Strings.Designer.cs index 71fb1ef74bc..89830cc2724 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.CommandLine.XPlat/Strings.Designer.cs +++ b/src/nuget-client/src/NuGet.Core/NuGet.CommandLine.XPlat/Strings.Designer.cs @@ -573,6 +573,25 @@ internal static string Error_ConfigSetInvalidKey { } } + /// + /// Looks up a localized string similar to You are running the '{0}' operation with an 'HTTP' source, '{1}'. NuGet requires HTTPS sources. To use HTTP sources, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information.. + /// + internal static string Error_HttpServerUsage { + get { + return ResourceManager.GetString("Error_HttpServerUsage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You are running the '{0}' operation with 'HTTP' sources: {1} + ///NuGet requires HTTPS sources. To use HTTP sources, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information.. + /// + internal static string Error_HttpServerUsage_MultipleSources { + get { + return ResourceManager.GetString("Error_HttpServerUsage_MultipleSources", resourceCulture); + } + } + /// /// Looks up a localized string similar to Invalid culture identifier in {0} environment variable. Value read is '{1}'. /// @@ -2240,25 +2259,6 @@ internal static string Warning_AuditSourceWithoutData { } } - /// - /// Looks up a localized string similar to You are running the '{0}' operation with an 'HTTP' source, '{1}'. Non-HTTPS access will be removed in a future version. Consider migrating to an 'HTTPS' source.. - /// - internal static string Warning_HttpServerUsage { - get { - return ResourceManager.GetString("Warning_HttpServerUsage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You are running the '{0}' operation with 'HTTP' sources: {1} - ///Non-HTTPS access will be removed in a future version. Consider migrating to 'HTTPS' sources.. - /// - internal static string Warning_HttpServerUsage_MultipleSources { - get { - return ResourceManager.GetString("Warning_HttpServerUsage_MultipleSources", resourceCulture); - } - } - /// /// Looks up a localized string similar to Shows the dependency graph for a particular package for a given project or solution.. /// diff --git a/src/nuget-client/src/NuGet.Core/NuGet.CommandLine.XPlat/Strings.resx b/src/nuget-client/src/NuGet.Core/NuGet.CommandLine.XPlat/Strings.resx index 235d1bcae30..338abfcbccc 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.CommandLine.XPlat/Strings.resx +++ b/src/nuget-client/src/NuGet.Core/NuGet.CommandLine.XPlat/Strings.resx @@ -741,13 +741,13 @@ The search is a case-insensitive string comparison using the supplied value, whi The certificate finger you're trying to add is already in the certificate fingerprint list. - - You are running the '{0}' operation with an 'HTTP' source, '{1}'. Non-HTTPS access will be removed in a future version. Consider migrating to an 'HTTPS' source. + + You are running the '{0}' operation with an 'HTTP' source, '{1}'. NuGet requires HTTPS sources. To use HTTP sources, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information. 0 - The command name. Ex. Push/Delete. 1 - server uri. - + You are running the '{0}' operation with 'HTTP' sources: {1} -Non-HTTPS access will be removed in a future version. Consider migrating to 'HTTPS' sources. +NuGet requires HTTPS sources. To use HTTP sources, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information. 0 - The command name. Ex. Push/Delete. 1 - list of server uris diff --git a/src/nuget-client/src/NuGet.Core/NuGet.CommandLine.XPlat/Utility/HttpSourcesUtility.cs b/src/nuget-client/src/NuGet.Core/NuGet.CommandLine.XPlat/Utility/HttpSourcesUtility.cs new file mode 100644 index 00000000000..a6c77b1de39 --- /dev/null +++ b/src/nuget-client/src/NuGet.Core/NuGet.CommandLine.XPlat/Utility/HttpSourcesUtility.cs @@ -0,0 +1,59 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using NuGet.Configuration; + +namespace NuGet.CommandLine.XPlat.Utility +{ + internal static class HttpSourcesUtility + { + public static List GetDisallowedInsecureHttpSources(IReadOnlyList packageSources) + { + if (packageSources == null || packageSources.Count == 0) + { + return new(); + } + + List httpPackageSources = null; + + foreach (PackageSource packageSource in packageSources) + { + if (packageSource.IsHttp && !packageSource.IsHttps && !packageSource.AllowInsecureConnections) + { + httpPackageSources ??= new(capacity: packageSources.Count); + httpPackageSources.Add(packageSource); + } + } + + return httpPackageSources ?? new(); + } + + public static string BuildHttpSourceErrorMessage(List httpSources, string commandName) + { + string error = null; + + if (httpSources.Count == 1) + { + error = string.Format( + CultureInfo.CurrentCulture, + Strings.Error_HttpServerUsage, + commandName, + httpSources[0]); + } + else if (httpSources.Count > 1) + { + error = string.Format( + CultureInfo.CurrentCulture, + Strings.Error_HttpServerUsage_MultipleSources, + commandName, + Environment.NewLine + string.Join(Environment.NewLine, httpSources.Select(e => e.Name))); + } + + return error; + } + } +} diff --git a/src/nuget-client/src/NuGet.Core/NuGet.Commands/CommandRunners/PackCommandRunner.cs b/src/nuget-client/src/NuGet.Core/NuGet.Commands/CommandRunners/PackCommandRunner.cs index 9cdb2be425f..470bc5ca07d 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.Commands/CommandRunners/PackCommandRunner.cs +++ b/src/nuget-client/src/NuGet.Core/NuGet.Commands/CommandRunners/PackCommandRunner.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Globalization; using System.IO; using System.Linq; @@ -322,249 +321,6 @@ private void InitCommonPackageBuilderProperties(PackageBuilder builder) ExcludeFiles(builder.Files); } - [Obsolete] - public static bool ProcessProjectJsonFile( - PackageBuilder builder, - string basePath, - string id, - NuGetVersion version, - string suffix, - Func propertyProvider) - { - if (basePath == null) - { - return false; - } - - string path = ProjectJsonPathUtilities.GetProjectConfigPath(basePath, Path.GetFileName(basePath)); - if (File.Exists(path)) - { - using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read)) - { - LoadProjectJsonFile(builder, path, basePath, id, stream, version, suffix); - } - return true; - } - - return false; - } - - [Obsolete] - private static void LoadProjectJsonFile( - PackageBuilder builder, - string path, - string basePath, - string id, - Stream stream, - NuGetVersion version, - string suffix) - { - PackageSpec spec = JsonPackageSpecReader.GetPackageSpec(stream, id, path, suffix); - - if (id == null) - { - builder.Id = Path.GetFileName(basePath); - } - else - { - builder.Id = id; - } - if (version != null) - { - builder.Version = version; - builder.HasSnapshotVersion = false; - } - else if (!spec.IsDefaultVersion) - { - builder.Version = spec.Version; - builder.HasSnapshotVersion = spec.HasVersionSnapshot; - - if (suffix != null && !spec.HasVersionSnapshot) - { - builder.Version = new NuGetVersion( - builder.Version.Major, - builder.Version.Minor, - builder.Version.Patch, - builder.Version.Revision, - suffix, - metadata: null); - } - } - if (spec.Title != null) - { - builder.Title = spec.Title; - } - if (spec.Description != null) - { - builder.Description = spec.Description; - } - if (spec.Copyright != null) - { - builder.Copyright = spec.Copyright; - } - if (spec.Authors.Any()) - { - builder.Authors.AddRange(spec.Authors); - } - if (spec.Owners.Any()) - { - builder.Owners.AddRange(spec.Owners); - } - Uri tempUri; - if (Uri.TryCreate(spec.LicenseUrl, UriKind.Absolute, out tempUri)) - { - builder.LicenseUrl = tempUri; - } - if (Uri.TryCreate(spec.ProjectUrl, UriKind.Absolute, out tempUri)) - { - builder.ProjectUrl = tempUri; - } - if (Uri.TryCreate(spec.IconUrl, UriKind.Absolute, out tempUri)) - { - builder.IconUrl = tempUri; - } - builder.RequireLicenseAcceptance = spec.RequireLicenseAcceptance; - if (spec.Summary != null) - { - builder.Summary = spec.Summary; - } - if (spec.ReleaseNotes != null) - { - builder.ReleaseNotes = spec.ReleaseNotes; - } - if (spec.Language != null) - { - builder.Language = spec.Language; - } - if (spec.BuildOptions != null && spec.BuildOptions.OutputName != null) - { - builder.OutputName = spec.BuildOptions.OutputName; - } - - foreach (KeyValuePair include in spec.PackInclude) - { - builder.AddFiles(basePath, include.Value, include.Key); - } - - if (spec.PackOptions != null) - { - if (spec.PackOptions.IncludeExcludeFiles != null) - { - string fullExclude; - string filesExclude; - CalculateExcludes(spec.PackOptions.IncludeExcludeFiles, out fullExclude, out filesExclude); - - if (spec.PackOptions.IncludeExcludeFiles.Include != null) - { - foreach (string include in spec.PackOptions.IncludeExcludeFiles.Include) - { - builder.AddFiles(basePath, include, string.Empty, fullExclude); - } - } - - if (spec.PackOptions.IncludeExcludeFiles.IncludeFiles != null) - { - foreach (string includeFile in spec.PackOptions.IncludeExcludeFiles.IncludeFiles) - { - string resolvedPath = ResolvePath(new PhysicalPackageFile() { SourcePath = includeFile }, basePath); - - builder.AddFiles(basePath, includeFile, resolvedPath, filesExclude); - } - } - } - - if (spec.PackOptions.Mappings != null) - { - foreach (KeyValuePair map in spec.PackOptions.Mappings) - { - string fullExclude; - string filesExclude; - CalculateExcludes(map.Value, out fullExclude, out filesExclude); - - if (map.Value.Include != null) - { - // Include paths from project.json are glob matching strings. - // Calling AddFiles for "path/**" with an output target of "newpath/" - // should go to "newpath/filename" but instead goes to "newpath/path/filename". - // To get around this, do a WildcardSearch ahead of the AddFiles to get full paths. - // Passing in the target path will then what we want. - foreach (string include in map.Value.Include) - { - IEnumerable matchedFiles = PathResolver.PerformWildcardSearch(basePath, include); - foreach (var matchedFile in matchedFiles) - { - builder.AddFiles(basePath, matchedFile, map.Key, fullExclude); - } - } - } - - if (map.Value.IncludeFiles != null) - { - foreach (string include in map.Value.IncludeFiles) - { - builder.AddFiles(basePath, include, map.Key, filesExclude); - } - } - } - } - } - - if (spec.Tags.Any()) - { - builder.Tags.AddRange(spec.Tags); - } - - if (spec.TargetFrameworks.Any()) - { - foreach (TargetFrameworkInformation framework in spec.TargetFrameworks) - { - if (framework.FrameworkName.IsUnsupported) - { - throw new PackagingException( - NuGetLogCode.NU5003, - string.Format( - CultureInfo.CurrentCulture, - Strings.Error_InvalidTargetFramework, - framework.FrameworkName)); - } - - builder.TargetFrameworks.Add(framework.FrameworkName); - AddDependencyGroups(framework.Dependencies.Concat(spec.Dependencies), framework.FrameworkName, builder); - } - } - else - { - if (spec.Dependencies.Any()) - { - AddDependencyGroups(spec.Dependencies, NuGetFramework.AnyFramework, builder); - } - } - - builder.PackageTypes = new Collection(spec.PackOptions?.PackageType?.ToList() ?? new List()); - } - - private static void CalculateExcludes(IncludeExcludeFiles files, out string fullExclude, out string filesExclude) - { - fullExclude = string.Empty; - filesExclude = string.Empty; - if (files.Exclude != null && - files.Exclude.Any()) - { - fullExclude = string.Join(";", files.Exclude); - } - - if (files.ExcludeFiles != null && - files.ExcludeFiles.Any()) - { - if (!string.IsNullOrEmpty(fullExclude)) - { - fullExclude += ";"; - } - filesExclude += string.Join(";", files.ExcludeFiles); - fullExclude += filesExclude; - } - } - public static void AddDependencyGroups( IEnumerable dependencies, NuGetFramework framework, diff --git a/src/nuget-client/src/NuGet.Core/NuGet.Commands/GlobalSuppressions.cs b/src/nuget-client/src/NuGet.Core/NuGet.Commands/GlobalSuppressions.cs index 2600657f81e..3a496e50af9 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.Commands/GlobalSuppressions.cs +++ b/src/nuget-client/src/NuGet.Core/NuGet.Commands/GlobalSuppressions.cs @@ -97,8 +97,6 @@ [assembly: SuppressMessage("Build", "CA1062:In externally visible method 'string PackCommandRunner.GetOutputFileName(string packageId, NuGetVersion version, bool isNupkg, bool symbols, SymbolPackageFormat symbolPackageFormat, bool excludeVersion = false)', validate parameter 'version' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "", Scope = "member", Target = "~M:NuGet.Commands.PackCommandRunner.GetOutputFileName(System.String,NuGet.Versioning.NuGetVersion,System.Boolean,System.Boolean,NuGet.Commands.SymbolPackageFormat,System.Boolean)~System.String")] [assembly: SuppressMessage("Build", "CA1062:In externally visible method 'string PackCommandRunner.GetOutputPath(PackageBuilder builder, PackArgs packArgs, bool symbols = false, NuGetVersion nugetVersion = null, string outputDirectory = null, bool isNupkg = true)', validate parameter 'packArgs' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "", Scope = "member", Target = "~M:NuGet.Commands.PackCommandRunner.GetOutputPath(NuGet.Packaging.PackageBuilder,NuGet.Commands.PackArgs,System.Boolean,NuGet.Versioning.NuGetVersion,System.String,System.Boolean)~System.String")] [assembly: SuppressMessage("Build", "CA1303:Method 'void PackCommandRunner.PrintVerbose(string outputPath, PackageBuilder builder)' passes a literal string as parameter 'message' of a call to 'void PackCommandRunner.WriteLine(string message, object arg = null)'. Retrieve the following string(s) from a resource table instead: \"Version: {0}\".", Justification = "", Scope = "member", Target = "~M:NuGet.Commands.PackCommandRunner.PrintVerbose(System.String,NuGet.Packaging.PackageBuilder)")] -[assembly: SuppressMessage("Build", "CA1062:In externally visible method 'bool PackCommandRunner.ProcessProjectJsonFile(PackageBuilder builder, string basePath, string id, NuGetVersion version, string suffix, Func propertyProvider)', validate parameter 'builder' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "", Scope = "member", Target = "~M:NuGet.Commands.PackCommandRunner.ProcessProjectJsonFile(NuGet.Packaging.PackageBuilder,System.String,System.String,NuGet.Versioning.NuGetVersion,System.String,System.Func{System.String,System.String})~System.Boolean")] -[assembly: SuppressMessage("Build", "CA1801:Parameter propertyProvider of method ProcessProjectJsonFile is never used. Remove the parameter or use it in the method body.", Justification = "", Scope = "member", Target = "~M:NuGet.Commands.PackCommandRunner.ProcessProjectJsonFile(NuGet.Packaging.PackageBuilder,System.String,System.String,NuGet.Versioning.NuGetVersion,System.String,System.Func{System.String,System.String})~System.Boolean")] [assembly: SuppressMessage("Build", "CA1062:In externally visible method 'void PackCommandRunner.SetupCurrentDirectory(PackArgs packArgs)', validate parameter 'packArgs' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "", Scope = "member", Target = "~M:NuGet.Commands.PackCommandRunner.SetupCurrentDirectory(NuGet.Commands.PackArgs)")] [assembly: SuppressMessage("Build", "CA1062:In externally visible method 'Task PushRunner.Run(ISettings settings, IPackageSourceProvider sourceProvider, string packagePath, string source, string apiKey, string symbolSource, string symbolApiKey, int timeoutSeconds, bool disableBuffering, bool noSymbols, bool noServiceEndpoint, bool skipDuplicate, ILogger logger)', validate parameter 'sourceProvider' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "", Scope = "member", Target = "~M:NuGet.Commands.PushRunner.Run(NuGet.Configuration.ISettings,NuGet.Configuration.IPackageSourceProvider,System.String,System.String,System.String,System.String,System.String,System.Int32,System.Boolean,System.Boolean,System.Boolean,System.Boolean,NuGet.Common.ILogger)~System.Threading.Tasks.Task")] [assembly: SuppressMessage("Build", "CA1062:In externally visible method 'void RemoveSourceRunner.Run(RemoveSourceArgs args, Func getLogger)', validate parameter 'getLogger' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "", Scope = "member", Target = "~M:NuGet.Commands.RemoveSourceRunner.Run(NuGet.Commands.RemoveSourceArgs,System.Func{NuGet.Common.ILogger})")] diff --git a/src/nuget-client/src/NuGet.Core/NuGet.Commands/PublicAPI/net472/PublicAPI.Shipped.txt b/src/nuget-client/src/NuGet.Core/NuGet.Commands/PublicAPI/net472/PublicAPI.Shipped.txt index ae74211072c..c76134ecf19 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.Commands/PublicAPI/net472/PublicAPI.Shipped.txt +++ b/src/nuget-client/src/NuGet.Core/NuGet.Commands/PublicAPI/net472/PublicAPI.Shipped.txt @@ -977,7 +977,6 @@ override NuGet.Commands.WarningPropertiesCollection.GetHashCode() -> int ~static NuGet.Commands.PackCommandRunner.GetInputFile(NuGet.Commands.PackArgs packArgs) -> string ~static NuGet.Commands.PackCommandRunner.GetOutputFileName(string packageId, NuGet.Versioning.NuGetVersion version, bool isNupkg, bool symbols, NuGet.Commands.SymbolPackageFormat symbolPackageFormat, bool excludeVersion = false) -> string ~static NuGet.Commands.PackCommandRunner.GetOutputPath(NuGet.Packaging.PackageBuilder builder, NuGet.Commands.PackArgs packArgs, bool symbols = false, NuGet.Versioning.NuGetVersion nugetVersion = null, string outputDirectory = null, bool isNupkg = true) -> string -~static NuGet.Commands.PackCommandRunner.ProcessProjectJsonFile(NuGet.Packaging.PackageBuilder builder, string basePath, string id, NuGet.Versioning.NuGetVersion version, string suffix, System.Func propertyProvider) -> bool ~static NuGet.Commands.PackCommandRunner.SetupCurrentDirectory(NuGet.Commands.PackArgs packArgs) -> void ~static NuGet.Commands.PackageSourceProviderExtensions.ResolveAndValidateSource(this NuGet.Configuration.IPackageSourceProvider sourceProvider, string source) -> string ~static NuGet.Commands.PackageSourceProviderExtensions.ResolveSource(System.Collections.Generic.IEnumerable availableSources, string source) -> NuGet.Configuration.PackageSource diff --git a/src/nuget-client/src/NuGet.Core/NuGet.Commands/PublicAPI/net8.0/PublicAPI.Shipped.txt b/src/nuget-client/src/NuGet.Core/NuGet.Commands/PublicAPI/net8.0/PublicAPI.Shipped.txt index 6854dd9a604..a817d792b85 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.Commands/PublicAPI/net8.0/PublicAPI.Shipped.txt +++ b/src/nuget-client/src/NuGet.Core/NuGet.Commands/PublicAPI/net8.0/PublicAPI.Shipped.txt @@ -976,7 +976,6 @@ override NuGet.Commands.WarningPropertiesCollection.GetHashCode() -> int ~static NuGet.Commands.PackCommandRunner.GetInputFile(NuGet.Commands.PackArgs packArgs) -> string ~static NuGet.Commands.PackCommandRunner.GetOutputFileName(string packageId, NuGet.Versioning.NuGetVersion version, bool isNupkg, bool symbols, NuGet.Commands.SymbolPackageFormat symbolPackageFormat, bool excludeVersion = false) -> string ~static NuGet.Commands.PackCommandRunner.GetOutputPath(NuGet.Packaging.PackageBuilder builder, NuGet.Commands.PackArgs packArgs, bool symbols = false, NuGet.Versioning.NuGetVersion nugetVersion = null, string outputDirectory = null, bool isNupkg = true) -> string -~static NuGet.Commands.PackCommandRunner.ProcessProjectJsonFile(NuGet.Packaging.PackageBuilder builder, string basePath, string id, NuGet.Versioning.NuGetVersion version, string suffix, System.Func propertyProvider) -> bool ~static NuGet.Commands.PackCommandRunner.SetupCurrentDirectory(NuGet.Commands.PackArgs packArgs) -> void ~static NuGet.Commands.PackageSourceProviderExtensions.ResolveAndValidateSource(this NuGet.Configuration.IPackageSourceProvider sourceProvider, string source) -> string ~static NuGet.Commands.PackageSourceProviderExtensions.ResolveSource(System.Collections.Generic.IEnumerable availableSources, string source) -> NuGet.Configuration.PackageSource diff --git a/src/nuget-client/src/NuGet.Core/NuGet.Commands/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt b/src/nuget-client/src/NuGet.Core/NuGet.Commands/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt index 4142afcb9b8..16d0c147695 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.Commands/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt +++ b/src/nuget-client/src/NuGet.Core/NuGet.Commands/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt @@ -975,7 +975,6 @@ override NuGet.Commands.WarningPropertiesCollection.GetHashCode() -> int ~static NuGet.Commands.PackCommandRunner.GetInputFile(NuGet.Commands.PackArgs packArgs) -> string ~static NuGet.Commands.PackCommandRunner.GetOutputFileName(string packageId, NuGet.Versioning.NuGetVersion version, bool isNupkg, bool symbols, NuGet.Commands.SymbolPackageFormat symbolPackageFormat, bool excludeVersion = false) -> string ~static NuGet.Commands.PackCommandRunner.GetOutputPath(NuGet.Packaging.PackageBuilder builder, NuGet.Commands.PackArgs packArgs, bool symbols = false, NuGet.Versioning.NuGetVersion nugetVersion = null, string outputDirectory = null, bool isNupkg = true) -> string -~static NuGet.Commands.PackCommandRunner.ProcessProjectJsonFile(NuGet.Packaging.PackageBuilder builder, string basePath, string id, NuGet.Versioning.NuGetVersion version, string suffix, System.Func propertyProvider) -> bool ~static NuGet.Commands.PackCommandRunner.SetupCurrentDirectory(NuGet.Commands.PackArgs packArgs) -> void ~static NuGet.Commands.PackageSourceProviderExtensions.ResolveAndValidateSource(this NuGet.Configuration.IPackageSourceProvider sourceProvider, string source) -> string ~static NuGet.Commands.PackageSourceProviderExtensions.ResolveSource(System.Collections.Generic.IEnumerable availableSources, string source) -> NuGet.Configuration.PackageSource diff --git a/src/nuget-client/src/NuGet.Core/NuGet.Commands/Strings.Designer.cs b/src/nuget-client/src/NuGet.Core/NuGet.Commands/Strings.Designer.cs index 5401b7e4174..a60c9da7e19 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.Commands/Strings.Designer.cs +++ b/src/nuget-client/src/NuGet.Core/NuGet.Commands/Strings.Designer.cs @@ -2545,16 +2545,6 @@ internal static string Warning_HttpServerUsage { } } - /// - /// Looks up a localized string similar to You are running the '{0}' operation with 'HTTP' sources: {1} - ///Non-HTTPS access will be removed in a future version. Consider migrating to 'HTTPS' sources.. - /// - internal static string Warning_HttpServerUsage_MultipleSources { - get { - return ResourceManager.GetString("Warning_HttpServerUsage_MultipleSources", resourceCulture); - } - } - /// /// Looks up a localized string similar to The following is a 'Non-HTTPS' source: {0} ///NuGet requires HTTPS sources. Refer to https://aka.ms/nuget-https-everywhere for more information.. diff --git a/src/nuget-client/src/NuGet.Core/NuGet.Commands/Strings.resx b/src/nuget-client/src/NuGet.Core/NuGet.Commands/Strings.resx index 6155f2af912..d674e4f0e21 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.Commands/Strings.resx +++ b/src/nuget-client/src/NuGet.Core/NuGet.Commands/Strings.resx @@ -1030,11 +1030,6 @@ For more information, visit https://docs.nuget.org/docs/reference/command-line-r You are running the '{0}' operation with an 'HTTP' source, '{1}'. Non-HTTPS access will be removed in a future version. Consider migrating to an 'HTTPS' source. 0 - The command name. Ex. Push/Delete. 1 - server URI. - - You are running the '{0}' operation with 'HTTP' sources: {1} -Non-HTTPS access will be removed in a future version. Consider migrating to 'HTTPS' sources. - 0 - The command name. Ex. Push/Delete. 1 - list of server URIs - Warning As Error: {0} {0} is a warning message diff --git a/src/nuget-client/src/NuGet.Core/NuGet.Common/Errors/NuGetLogCode.cs b/src/nuget-client/src/NuGet.Core/NuGet.Common/Errors/NuGetLogCode.cs index 8d0dfd0dbc5..34c09ecf030 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.Common/Errors/NuGetLogCode.cs +++ b/src/nuget-client/src/NuGet.Core/NuGet.Common/Errors/NuGetLogCode.cs @@ -1,6 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; + namespace NuGet.Common { /// @@ -700,6 +702,7 @@ public enum NuGetLogCode /// /// Error_MultipleTargetFrameworks /// + [Obsolete] NU5015 = 5015, /// diff --git a/src/nuget-client/src/NuGet.Core/NuGet.PackageManagement/NuGet.PackageManagement.csproj b/src/nuget-client/src/NuGet.Core/NuGet.PackageManagement/NuGet.PackageManagement.csproj index d355f79d45d..794901cae50 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.PackageManagement/NuGet.PackageManagement.csproj +++ b/src/nuget-client/src/NuGet.Core/NuGet.PackageManagement/NuGet.PackageManagement.csproj @@ -66,6 +66,7 @@ + diff --git a/src/nuget-client/src/NuGet.Core/NuGet.PackageManagement/NuGetPackageManager.cs b/src/nuget-client/src/NuGet.Core/NuGet.PackageManagement/NuGetPackageManager.cs index eff1aeedc40..5367ac1f81a 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.PackageManagement/NuGetPackageManager.cs +++ b/src/nuget-client/src/NuGet.Core/NuGet.PackageManagement/NuGetPackageManager.cs @@ -69,6 +69,11 @@ public class NuGetPackageManager /// public event EventHandler BatchEnd; + /// + /// The telemetry service to use for telemetry events. The setter is exposed for test purposes. + /// + internal INuGetTelemetryService NuGetTelemetryService { get; set; } + /// /// To construct a NuGetPackageManager that does not need a SolutionManager like NuGet.exe /// @@ -96,6 +101,7 @@ public NuGetPackageManager( InstallationCompatibility = PackageManagement.InstallationCompatibility.Instance; InitializePackagesFolderInfo(packagesFolderPath, excludeVersion); + NuGetTelemetryService = TelemetryActivity.NuGetTelemetryService; } /// @@ -146,6 +152,7 @@ public NuGetPackageManager( InitializePackagesFolderInfo(PackagesFolderPathUtility.GetPackagesFolderPath(SolutionManager, Settings), excludeVersion); DeleteOnRestartManager = deleteOnRestartManager ?? throw new ArgumentNullException(nameof(deleteOnRestartManager)); RestoreProgressReporter = reporter; + NuGetTelemetryService = TelemetryActivity.NuGetTelemetryService; } /// @@ -1172,7 +1179,7 @@ private async Task> PreviewUpdatePackagesForClas TelemetryConstants.GatherDependencyStepName, stopWatch.Elapsed.TotalSeconds); - TelemetryActivity.EmitTelemetryEvent(gatherTelemetryEvent); + NuGetTelemetryService?.EmitTelemetryEvent(gatherTelemetryEvent); stopWatch.Restart(); if (!availablePackageDependencyInfoWithSourceSet.Any()) @@ -1265,7 +1272,7 @@ private async Task> PreviewUpdatePackagesForClas TelemetryConstants.ResolveDependencyStepName, stopWatch.Elapsed.TotalSeconds); - TelemetryActivity.EmitTelemetryEvent(resolveTelemetryEvent); + NuGetTelemetryService?.EmitTelemetryEvent(resolveTelemetryEvent); stopWatch.Restart(); if (newListOfInstalledPackages == null) @@ -1304,7 +1311,7 @@ private async Task> PreviewUpdatePackagesForClas TelemetryConstants.ResolvedActionsStepName, stopWatch.Elapsed.TotalSeconds); - TelemetryActivity.EmitTelemetryEvent(actionTelemetryEvent); + NuGetTelemetryService?.EmitTelemetryEvent(actionTelemetryEvent); if (nuGetProjectActions.Count == 0) { @@ -1871,7 +1878,7 @@ await PreviewBuildIntegratedProjectActionsAsync(buildIntegratedProject, actions, TelemetryConstants.GatherDependencyStepName, stopWatch.Elapsed.TotalSeconds); - TelemetryActivity.EmitTelemetryEvent(gatherTelemetryEvent); + NuGetTelemetryService?.EmitTelemetryEvent(gatherTelemetryEvent); stopWatch.Restart(); @@ -1940,7 +1947,7 @@ await PreviewBuildIntegratedProjectActionsAsync(buildIntegratedProject, actions, TelemetryConstants.ResolveDependencyStepName, stopWatch.Elapsed.TotalSeconds); - TelemetryActivity.EmitTelemetryEvent(resolveTelemetryEvent); + NuGetTelemetryService?.EmitTelemetryEvent(resolveTelemetryEvent); stopWatch.Restart(); @@ -2034,7 +2041,7 @@ await PreviewBuildIntegratedProjectActionsAsync(buildIntegratedProject, actions, TelemetryConstants.ResolvedActionsStepName, stopWatch.Elapsed.TotalSeconds); - TelemetryActivity.EmitTelemetryEvent(actionTelemetryEvent); + NuGetTelemetryService?.EmitTelemetryEvent(actionTelemetryEvent); nuGetProjectContext.Log(MessageLevel.Info, Strings.ResolvedActionsToInstallPackage, packageIdentity); return nuGetProjectActions; @@ -2815,7 +2822,7 @@ await ExecuteInstallAsync( nuGetProjectContext.OperationId.ToString(), TelemetryConstants.ExecuteActionStepName, stopWatch.Elapsed.TotalSeconds); - TelemetryActivity.EmitTelemetryEvent(actionTelemetryEvent); + NuGetTelemetryService?.EmitTelemetryEvent(actionTelemetryEvent); if (exceptionInfo != null) { @@ -3189,7 +3196,7 @@ internal async Task> PreviewBuildIntegratedProjectsA nuGetProjectContext.OperationId.ToString(), TelemetryConstants.PreviewBuildIntegratedStepName, stopWatch.Elapsed.TotalSeconds); - TelemetryActivity.EmitTelemetryEvent(actionTelemetryEvent); + NuGetTelemetryService?.EmitTelemetryEvent(actionTelemetryEvent); return result; } diff --git a/src/nuget-client/src/NuGet.Core/NuGet.PackageManagement/Strings.Designer.cs b/src/nuget-client/src/NuGet.Core/NuGet.PackageManagement/Strings.Designer.cs index 5a1b70875bf..e4de11d0885 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.PackageManagement/Strings.Designer.cs +++ b/src/nuget-client/src/NuGet.Core/NuGet.PackageManagement/Strings.Designer.cs @@ -942,15 +942,6 @@ internal static string Warning_FileModified { } } - /// - /// Looks up a localized string similar to You are running the '{0}' operation with an 'HTTP' source, '{1}'. Non-HTTPS access will be removed in a future version. Consider migrating to an 'HTTPS' source.. - /// - internal static string Warning_HttpServerUsage { - get { - return ResourceManager.GetString("Warning_HttpServerUsage", resourceCulture); - } - } - /// /// Looks up a localized string similar to Package '{0}' {1} has a known {2} severity vulnerability, {3}. /// diff --git a/src/nuget-client/src/NuGet.Core/NuGet.PackageManagement/Strings.resx b/src/nuget-client/src/NuGet.Core/NuGet.PackageManagement/Strings.resx index bf0e830b89a..90de0d2e7d7 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.PackageManagement/Strings.resx +++ b/src/nuget-client/src/NuGet.Core/NuGet.PackageManagement/Strings.resx @@ -429,10 +429,6 @@ Package source mapping match not found for package ID '{0}' {0} - package id - - You are running the '{0}' operation with an 'HTTP' source, '{1}'. Non-HTTPS access will be removed in a future version. Consider migrating to an 'HTTPS' source. - 0 - The command name. Ex. Push/Delete. 1 - server uri. - Error occurred while getting package vulnerability data: {0} diff --git a/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/BuildOptions.cs b/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/BuildOptions.cs deleted file mode 100644 index 0916b605540..00000000000 --- a/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/BuildOptions.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using NuGet.Shared; - -namespace NuGet.ProjectModel -{ - public class BuildOptions : IEquatable - { - public string OutputName { get; set; } - - public override int GetHashCode() - { - var hashCode = new HashCodeCombiner(); - - hashCode.AddObject(OutputName); - - return hashCode.CombinedHash; - } - - public override bool Equals(object obj) - { - return Equals(obj as BuildOptions); - } - - public bool Equals(BuildOptions other) - { - if (other == null) - { - return false; - } - - if (ReferenceEquals(this, other)) - { - return true; - } - - return OutputName == other.OutputName; - } - - public BuildOptions Clone() - { - var clone = new BuildOptions(); - clone.OutputName = OutputName; - return clone; - } - } -} diff --git a/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/GlobalSuppressions.cs b/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/GlobalSuppressions.cs index dafcc2b108f..2340325ae34 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/GlobalSuppressions.cs +++ b/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/GlobalSuppressions.cs @@ -24,7 +24,6 @@ [assembly: SuppressMessage("Build", "CA1062:In externally visible method 'void PackagesLockFileFormat.Write(TextWriter textWriter, PackagesLockFile lockFile)', validate parameter 'lockFile' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "", Scope = "member", Target = "~M:NuGet.ProjectModel.PackagesLockFileFormat.Write(System.IO.TextWriter,NuGet.ProjectModel.PackagesLockFile)")] [assembly: SuppressMessage("Build", "CA1062:In externally visible method 'string PackagesLockFileUtilities.GetNuGetLockFilePath(PackageSpec project)', validate parameter 'project' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "", Scope = "member", Target = "~M:NuGet.ProjectModel.PackagesLockFileUtilities.GetNuGetLockFilePath(NuGet.ProjectModel.PackageSpec)~System.String")] [assembly: SuppressMessage("Build", "CA1062:In externally visible method 'bool PackagesLockFileUtilities.IsLockFileStillValid(DependencyGraphSpec dgSpec, PackagesLockFile nuGetLockFile)', validate parameter 'dgSpec' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "", Scope = "member", Target = "~M:NuGet.ProjectModel.PackagesLockFileUtilities.IsLockFileStillValid(NuGet.ProjectModel.DependencyGraphSpec,NuGet.ProjectModel.PackagesLockFile)~System.Boolean")] -[assembly: SuppressMessage("Build", "CA1822:Member CloneScripts does not access instance data and can be marked as static (Shared in VisualBasic)", Justification = "", Scope = "member", Target = "~M:NuGet.ProjectModel.PackageSpec.CloneScripts(System.Collections.Generic.IDictionary{System.String,System.Collections.Generic.IEnumerable{System.String}})~System.Collections.Generic.IDictionary{System.String,System.Collections.Generic.IEnumerable{System.String}}")] [assembly: SuppressMessage("Build", "CA1062:In externally visible method 'TargetFrameworkInformation PackageSpecExtensions.GetTargetFramework(PackageSpec project, NuGetFramework targetFramework)', validate parameter 'project' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "", Scope = "member", Target = "~M:NuGet.ProjectModel.PackageSpecExtensions.GetTargetFramework(NuGet.ProjectModel.PackageSpec,NuGet.Frameworks.NuGetFramework)~NuGet.ProjectModel.TargetFrameworkInformation")] [assembly: SuppressMessage("Build", "CA1062:In externally visible method 'Library PackageSpecReferenceDependencyProvider.GetLibrary(LibraryRange libraryRange, NuGetFramework targetFramework)', validate parameter 'libraryRange' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "", Scope = "member", Target = "~M:NuGet.ProjectModel.PackageSpecReferenceDependencyProvider.GetLibrary(NuGet.LibraryModel.LibraryRange,NuGet.Frameworks.NuGetFramework)~NuGet.LibraryModel.Library")] [assembly: SuppressMessage("Build", "CA1062:In externally visible method 'NuGetVersion PackageSpecUtility.SpecifySnapshot(string version, string snapshotValue)', validate parameter 'version' is non-null before using it. If appropriate, throw an ArgumentNullException when the argument is null or add a Code Contract precondition asserting non-null argument.", Justification = "", Scope = "member", Target = "~M:NuGet.ProjectModel.PackageSpecUtility.SpecifySnapshot(System.String,System.String)~NuGet.Versioning.NuGetVersion")] @@ -62,15 +61,7 @@ [assembly: SuppressMessage("Build", "CA2227:Change 'ToolsAssemblies' to be read-only by removing the property setter.", Justification = "", Scope = "member", Target = "~P:NuGet.ProjectModel.LockFileTargetLibrary.ToolsAssemblies")] [assembly: SuppressMessage("Build", "CA2227:Change 'Targets' to be read-only by removing the property setter.", Justification = "", Scope = "member", Target = "~P:NuGet.ProjectModel.PackagesLockFile.Targets")] [assembly: SuppressMessage("Build", "CA2227:Change 'Dependencies' to be read-only by removing the property setter.", Justification = "", Scope = "member", Target = "~P:NuGet.ProjectModel.PackagesLockFileTarget.Dependencies")] -[assembly: SuppressMessage("Build", "CA1819:Properties should not return arrays", Justification = "", Scope = "member", Target = "~P:NuGet.ProjectModel.PackageSpec.Authors")] -[assembly: SuppressMessage("Build", "CA2227:Change 'ContentFiles' to be read-only by removing the property setter.", Justification = "", Scope = "member", Target = "~P:NuGet.ProjectModel.PackageSpec.ContentFiles")] [assembly: SuppressMessage("Build", "CA2227:Change 'Dependencies' to be read-only by removing the property setter.", Justification = "", Scope = "member", Target = "~P:NuGet.ProjectModel.PackageSpec.Dependencies")] -[assembly: SuppressMessage("Build", "CA1056:Change the type of property PackageSpec.IconUrl from string to System.Uri.", Justification = "", Scope = "member", Target = "~P:NuGet.ProjectModel.PackageSpec.IconUrl")] -[assembly: SuppressMessage("Build", "CA1056:Change the type of property PackageSpec.LicenseUrl from string to System.Uri.", Justification = "", Scope = "member", Target = "~P:NuGet.ProjectModel.PackageSpec.LicenseUrl")] -[assembly: SuppressMessage("Build", "CA1819:Properties should not return arrays", Justification = "", Scope = "member", Target = "~P:NuGet.ProjectModel.PackageSpec.Owners")] -[assembly: SuppressMessage("Build", "CA1056:Change the type of property PackageSpec.ProjectUrl from string to System.Uri.", Justification = "", Scope = "member", Target = "~P:NuGet.ProjectModel.PackageSpec.ProjectUrl")] -[assembly: SuppressMessage("Build", "CA1819:Properties should not return arrays", Justification = "", Scope = "member", Target = "~P:NuGet.ProjectModel.PackageSpec.Tags")] -[assembly: SuppressMessage("Build", "CA2227:Change 'Mappings' to be read-only by removing the property setter.", Justification = "", Scope = "member", Target = "~P:NuGet.ProjectModel.PackOptions.Mappings")] [assembly: SuppressMessage("Build", "CA2227:Change 'ConfigFilePaths' to be read-only by removing the property setter.", Justification = "", Scope = "member", Target = "~P:NuGet.ProjectModel.ProjectRestoreMetadata.ConfigFilePaths")] [assembly: SuppressMessage("Build", "CA2227:Change 'FallbackFolders' to be read-only by removing the property setter.", Justification = "", Scope = "member", Target = "~P:NuGet.ProjectModel.ProjectRestoreMetadata.FallbackFolders")] [assembly: SuppressMessage("Build", "CA2227:Change 'Files' to be read-only by removing the property setter.", Justification = "", Scope = "member", Target = "~P:NuGet.ProjectModel.ProjectRestoreMetadata.Files")] diff --git a/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/IncludeExcludeFiles.cs b/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/IncludeExcludeFiles.cs deleted file mode 100644 index 74e7b903f06..00000000000 --- a/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/IncludeExcludeFiles.cs +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using Newtonsoft.Json.Linq; -using NuGet.Shared; - -namespace NuGet.ProjectModel -{ - public class IncludeExcludeFiles : IEquatable - { - public IReadOnlyList Include { get; set; } - public IReadOnlyList Exclude { get; set; } - public IReadOnlyList IncludeFiles { get; set; } - public IReadOnlyList ExcludeFiles { get; set; } - - public bool HandleIncludeExcludeFiles(JObject jsonObject) - { - if (jsonObject == null) - { - throw new ArgumentNullException(nameof(jsonObject)); - } - - JToken rawInclude = jsonObject["include"]; - JToken rawExclude = jsonObject["exclude"]; - JToken rawIncludeFiles = jsonObject["includeFiles"]; - JToken rawExcludeFiles = jsonObject["excludeFiles"]; - - var foundOne = false; - - if (rawInclude != null && TryGetStringEnumerableFromJArray(rawInclude, out IReadOnlyList include)) - { - Include = include; - foundOne = true; - } - - if (rawExclude != null && TryGetStringEnumerableFromJArray(rawExclude, out IReadOnlyList exclude)) - { - Exclude = exclude; - foundOne = true; - } - - if (rawIncludeFiles != null && TryGetStringEnumerableFromJArray(rawIncludeFiles, out IReadOnlyList includeFiles)) - { - IncludeFiles = includeFiles; - foundOne = true; - } - - if (rawExcludeFiles != null && TryGetStringEnumerableFromJArray(rawExcludeFiles, out IReadOnlyList excludeFiles)) - { - ExcludeFiles = excludeFiles; - foundOne = true; - } - - return foundOne; - } - - public override int GetHashCode() - { - var hashCode = new HashCodeCombiner(); - - hashCode.AddSequence(Include); - hashCode.AddSequence(Exclude); - hashCode.AddSequence(IncludeFiles); - hashCode.AddSequence(ExcludeFiles); - - return hashCode.CombinedHash; - } - - public override bool Equals(object obj) - { - return Equals(obj as IncludeExcludeFiles); - } - - public bool Equals(IncludeExcludeFiles other) - { - if (other == null) - { - return false; - } - - if (ReferenceEquals(this, other)) - { - return true; - } - - return Include.SequenceEqualWithNullCheck(other.Include) && - Exclude.SequenceEqualWithNullCheck(other.Exclude) && - IncludeFiles.SequenceEqualWithNullCheck(other.IncludeFiles) && - ExcludeFiles.SequenceEqualWithNullCheck(other.ExcludeFiles); - } - - public IncludeExcludeFiles Clone() - { - var clonedObject = new IncludeExcludeFiles(); - clonedObject.Include = Include.ToList(); - clonedObject.Exclude = Exclude.ToList(); - clonedObject.IncludeFiles = IncludeFiles.ToList(); - clonedObject.ExcludeFiles = ExcludeFiles.ToList(); - return clonedObject; - } - - private static bool TryGetStringEnumerableFromJArray(JToken token, out IReadOnlyList result) - { - result = null; - - if (token == null) - { - return false; - } - else if (token.Type == JTokenType.String) - { - result = new[] - { - token.Value() - }; - } - else if (token.Type == JTokenType.Array) - { - result = token.ValueAsArray(); - } - else - { - return false; - } - - return true; - } - } -} diff --git a/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.Utf8JsonStreamReader.cs b/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.Utf8JsonStreamReader.cs index 378e949fca5..d2a8cfa0ec3 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.Utf8JsonStreamReader.cs +++ b/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.Utf8JsonStreamReader.cs @@ -22,23 +22,12 @@ namespace NuGet.ProjectModel { public partial class JsonPackageSpecReader { - private static readonly byte[] AuthorsPropertyName = Encoding.UTF8.GetBytes("authors"); - private static readonly byte[] BuildOptionsPropertyName = Encoding.UTF8.GetBytes("buildOptions"); - private static readonly byte[] ContentFilesPropertyName = Encoding.UTF8.GetBytes("contentFiles"); - private static readonly byte[] CopyrightPropertyName = Encoding.UTF8.GetBytes("copyright"); private static readonly byte[] DependenciesPropertyName = Encoding.UTF8.GetBytes("dependencies"); - private static readonly byte[] DescriptionPropertyName = Encoding.UTF8.GetBytes("description"); - private static readonly byte[] LanguagePropertyName = Encoding.UTF8.GetBytes("language"); - private static readonly byte[] PackIncludePropertyName = Encoding.UTF8.GetBytes("packInclude"); - private static readonly byte[] PackOptionsPropertyName = Encoding.UTF8.GetBytes("packOptions"); - private static readonly byte[] ScriptsPropertyName = Encoding.UTF8.GetBytes("scripts"); private static readonly byte[] FrameworksPropertyName = Encoding.UTF8.GetBytes("frameworks"); private static readonly byte[] RestorePropertyName = Encoding.UTF8.GetBytes("restore"); private static readonly byte[] RuntimesPropertyName = Encoding.UTF8.GetBytes("runtimes"); private static readonly byte[] SupportsPropertyName = Encoding.UTF8.GetBytes("supports"); - private static readonly byte[] TitlePropertyName = Encoding.UTF8.GetBytes("title"); private static readonly byte[] VersionPropertyName = Encoding.UTF8.GetBytes("version"); - private static readonly byte[] OutputNamePropertyName = Encoding.UTF8.GetBytes("outputName"); private static readonly byte[] AutoReferencedPropertyName = Encoding.UTF8.GetBytes("autoReferenced"); private static readonly byte[] ExcludePropertyName = Encoding.UTF8.GetBytes("exclude"); private static readonly byte[] GeneratePathPropertyPropertyName = Encoding.UTF8.GetBytes("generatePathProperty"); @@ -98,16 +87,6 @@ public partial class JsonPackageSpecReader private static readonly byte[] ImportsPropertyName = Encoding.UTF8.GetBytes("imports"); private static readonly byte[] RuntimeIdentifierGraphPathPropertyName = Encoding.UTF8.GetBytes("runtimeIdentifierGraphPath"); private static readonly byte[] WarnPropertyName = Encoding.UTF8.GetBytes("warn"); - private static readonly byte[] IconUrlPropertyName = Encoding.UTF8.GetBytes("iconUrl"); - private static readonly byte[] LicenseUrlPropertyName = Encoding.UTF8.GetBytes("licenseUrl"); - private static readonly byte[] OwnersPropertyName = Encoding.UTF8.GetBytes("owners"); - private static readonly byte[] PackageTypePropertyName = Encoding.UTF8.GetBytes("packageType"); - private static readonly byte[] ProjectUrlPropertyName = Encoding.UTF8.GetBytes("projectUrl"); - private static readonly byte[] ReleaseNotesPropertyName = Encoding.UTF8.GetBytes("releaseNotes"); - private static readonly byte[] RequireLicenseAcceptancePropertyName = Encoding.UTF8.GetBytes("requireLicenseAcceptance"); - private static readonly byte[] SummaryPropertyName = Encoding.UTF8.GetBytes("summary"); - private static readonly byte[] TagsPropertyName = Encoding.UTF8.GetBytes("tags"); - private static readonly byte[] MappingsPropertyName = Encoding.UTF8.GetBytes("mappings"); private static readonly byte[] HashTagImportPropertyName = Encoding.UTF8.GetBytes("#import"); private static readonly byte[] ProjectReferencesPropertyName = Encoding.UTF8.GetBytes("projectReferences"); private static readonly byte[] EmptyStringPropertyName = Encoding.UTF8.GetBytes(string.Empty); @@ -133,8 +112,6 @@ internal static PackageSpec GetPackageSpec(ref Utf8JsonStreamReader jsonReader, List compatibilityProfiles = null; List runtimeDescriptions = null; - var wasPackOptionsSet = false; - var isMappingsNull = false; string filePath = name == null ? null : Path.GetFullPath(packageSpecPath); if (jsonReader.TokenType == JsonTokenType.StartObject) @@ -145,51 +122,6 @@ internal static PackageSpec GetPackageSpec(ref Utf8JsonStreamReader jsonReader, { jsonReader.Skip(); } -#pragma warning disable CS0612 // Type or member is obsolete - else if (jsonReader.ValueTextEquals(AuthorsPropertyName)) - { - jsonReader.Read(); - if (jsonReader.TokenType == JsonTokenType.StartArray) - { - packageSpec.Authors = jsonReader.ReadStringArrayAsIList()?.ToArray(); - } - packageSpec.Authors ??= []; - } - else if (jsonReader.ValueTextEquals(BuildOptionsPropertyName)) - { - ReadBuildOptions(ref jsonReader, packageSpec); - } - else if (jsonReader.ValueTextEquals(ContentFilesPropertyName)) - { - jsonReader.Read(); - jsonReader.ReadStringArrayAsIList(packageSpec.ContentFiles); - } - else if (jsonReader.ValueTextEquals(CopyrightPropertyName)) - { - packageSpec.Copyright = jsonReader.ReadNextTokenAsString(); - } - else if (jsonReader.ValueTextEquals(DescriptionPropertyName)) - { - packageSpec.Description = jsonReader.ReadNextTokenAsString(); - } - else if (jsonReader.ValueTextEquals(LanguagePropertyName)) - { - packageSpec.Language = jsonReader.ReadNextTokenAsString(); - } - else if (jsonReader.ValueTextEquals(PackIncludePropertyName)) - { - ReadPackInclude(ref jsonReader, packageSpec); - } - else if (jsonReader.ValueTextEquals(PackOptionsPropertyName)) - { - ReadPackOptions(ref jsonReader, packageSpec, ref isMappingsNull); - wasPackOptionsSet = true; - } - else if (jsonReader.ValueTextEquals(ScriptsPropertyName)) - { - ReadScripts(ref jsonReader, packageSpec); - } -#pragma warning restore CS0612 // Type or member is else if (jsonReader.ValueTextEquals(DependenciesPropertyName)) { ReadDependencies( @@ -214,10 +146,6 @@ internal static PackageSpec GetPackageSpec(ref Utf8JsonStreamReader jsonReader, { compatibilityProfiles = ReadSupports(ref jsonReader); } - else if (jsonReader.ValueTextEquals(TitlePropertyName)) - { - packageSpec.Title = jsonReader.ReadNextTokenAsString(); - } else if (jsonReader.ValueTextEquals(VersionPropertyName)) { string version = jsonReader.ReadNextTokenAsString(); @@ -225,9 +153,6 @@ internal static PackageSpec GetPackageSpec(ref Utf8JsonStreamReader jsonReader, { try { -#pragma warning disable CS0612 // Type or member is obsolete - packageSpec.HasVersionSnapshot = PackageSpecUtility.IsSnapshotVersion(version); -#pragma warning restore CS0612 // Type or member is obsolete packageSpec.Version = PackageSpecUtility.SpecifySnapshot(version, snapshotValue); } catch (Exception ex) @@ -245,23 +170,6 @@ internal static PackageSpec GetPackageSpec(ref Utf8JsonStreamReader jsonReader, packageSpec.Name = name; packageSpec.FilePath = name == null ? null : Path.GetFullPath(packageSpecPath); -#pragma warning disable CS0612 // Type or member is obsolete - if (!wasPackOptionsSet) - { - packageSpec.Owners = []; - packageSpec.PackOptions = new PackOptions() - { - PackageType = Array.Empty() - }; - packageSpec.Tags = []; - } - - if (isMappingsNull) - { - packageSpec.PackOptions.Mappings = null; - } -#pragma warning restore CS0612 // Type or member is obsolete - packageSpec.RuntimeGraph = new RuntimeGraph( runtimeDescriptions ?? Enumerable.Empty(), compatibilityProfiles ?? Enumerable.Empty()); @@ -592,27 +500,6 @@ private static PackageType CreatePackageType(ref Utf8JsonStreamReader jsonReader return new PackageType(name, Packaging.Core.PackageType.EmptyVersion); } - [Obsolete] - private static void ReadBuildOptions(ref Utf8JsonStreamReader jsonReader, PackageSpec packageSpec) - { - packageSpec.BuildOptions = new BuildOptions(); - - if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) - { - while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) - { - if (jsonReader.ValueTextEquals(OutputNamePropertyName)) - { - packageSpec.BuildOptions.OutputName = jsonReader.ReadNextTokenAsString(); - } - else - { - jsonReader.Skip(); - } - } - } - } - private static void ReadCentralPackageVersions( ref Utf8JsonStreamReader jsonReader, IDictionary centralPackageVersions, @@ -862,7 +749,7 @@ private static void ReadImports(PackageSpec packageSpec, ref Utf8JsonStreamReade CultureInfo.CurrentCulture, Strings.Log_InvalidImportFramework, import, - PackageSpec.PackageSpecFileName), + packageSpec.FilePath), packageSpec.FilePath); } @@ -871,83 +758,6 @@ private static void ReadImports(PackageSpec packageSpec, ref Utf8JsonStreamReade } } - private static void ReadMappings(ref Utf8JsonStreamReader jsonReader, string mappingKey, IDictionary mappings) - { - if (jsonReader.Read()) - { - switch (jsonReader.TokenType) - { - case JsonTokenType.String: - { - var files = new IncludeExcludeFiles() - { - Include = new[] { jsonReader.GetString() } - }; - - mappings.Add(mappingKey, files); - } - break; - case JsonTokenType.StartArray: - { - IReadOnlyList include = jsonReader.ReadStringArrayAsReadOnlyListFromArrayStart(); - - var files = new IncludeExcludeFiles() - { - Include = include - }; - - mappings.Add(mappingKey, files); - } - break; - case JsonTokenType.StartObject: - { - IReadOnlyList excludeFiles = null; - IReadOnlyList exclude = null; - IReadOnlyList includeFiles = null; - IReadOnlyList include = null; - - while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) - { - if (jsonReader.ValueTextEquals(ExcludeFilesPropertyName)) - { - excludeFiles = jsonReader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); - } - else if (jsonReader.ValueTextEquals(ExcludePropertyName)) - { - exclude = jsonReader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); - } - else if (jsonReader.ValueTextEquals(IncludeFilesPropertyName)) - { - includeFiles = jsonReader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); - } - else if (jsonReader.ValueTextEquals(IncludePropertyName)) - { - include = jsonReader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); - } - else - { - jsonReader.Skip(); - } - } - - if (include != null || includeFiles != null || exclude != null || excludeFiles != null) - { - var files = new IncludeExcludeFiles() - { - ExcludeFiles = excludeFiles, - Exclude = exclude, - IncludeFiles = includeFiles, - Include = include - }; - - mappings.Add(mappingKey, files); - } - } - break; - } - } - } - private static void ReadMSBuildMetadata(ref Utf8JsonStreamReader jsonReader, PackageSpec packageSpec, IEnvironmentVariableReader environmentVariableReader) { var centralPackageVersionsManagementEnabled = false; @@ -1380,214 +1190,6 @@ private static ImmutableArray ReadNuGetLogCodesList(ref Utf8JsonSt return retVal; } - private static void ReadPackageTypes(PackageSpec packageSpec, ref Utf8JsonStreamReader jsonReader) - { - IReadOnlyList packageTypes = null; - try - { - if (jsonReader.Read()) - { - PackageType packageType; - switch (jsonReader.TokenType) - { - case JsonTokenType.String: - packageType = CreatePackageType(ref jsonReader); - packageTypes = new[] { packageType }; - break; - case JsonTokenType.StartArray: - List types = null; - - while (jsonReader.Read() && jsonReader.TokenType != JsonTokenType.EndArray) - { - if (jsonReader.TokenType != JsonTokenType.String) - { - throw FileFormatException.Create( - string.Format( - CultureInfo.CurrentCulture, - Strings.InvalidPackageType, - PackageSpec.PackageSpecFileName), - packageSpec.FilePath); - } - - packageType = CreatePackageType(ref jsonReader); - types ??= []; - types.Add(packageType); - } - - packageTypes = types; - break; - case JsonTokenType.Null: - break; - default: - throw new InvalidCastException(); - } - -#pragma warning disable CS0612 // Type or member is obsolete - if (packageTypes != null) - { - packageSpec.PackOptions.PackageType = packageTypes; - } -#pragma warning restore CS0612 // Type or member is obsolete - } - } - catch (Exception) - { - throw FileFormatException.Create( - string.Format( - CultureInfo.CurrentCulture, - Strings.InvalidPackageType, - PackageSpec.PackageSpecFileName), - packageSpec.FilePath); - } - } - - [Obsolete] - private static void ReadPackInclude(ref Utf8JsonStreamReader jsonReader, PackageSpec packageSpec) - { - if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) - { - while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) - { - string propertyName = jsonReader.GetString(); - string propertyValue = jsonReader.ReadNextTokenAsString(); - - packageSpec.PackInclude.Add(new KeyValuePair(propertyName, propertyValue)); - } - } - } - - [Obsolete] - private static void ReadPackOptions(ref Utf8JsonStreamReader jsonReader, PackageSpec packageSpec, ref bool isMappingsNull) - { - var wasMappingsRead = false; - bool isPackOptionsValueAnObject = false; - - if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) - { - isPackOptionsValueAnObject = true; - while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) - { - if (jsonReader.ValueTextEquals(FilesPropertyName)) - { - wasMappingsRead = ReadPackOptionsFiles(packageSpec, ref jsonReader, wasMappingsRead); - } - else if (jsonReader.ValueTextEquals(IconUrlPropertyName)) - { - packageSpec.IconUrl = jsonReader.ReadNextTokenAsString(); - } - else if (jsonReader.ValueTextEquals(LicenseUrlPropertyName)) - { - packageSpec.LicenseUrl = jsonReader.ReadNextTokenAsString(); - } - else if (jsonReader.ValueTextEquals(OwnersPropertyName)) - { - jsonReader.Read(); - string[] owners = jsonReader.ReadStringArrayAsIList()?.ToArray(); - if (owners != null) - { - packageSpec.Owners = owners; - } - } - else if (jsonReader.ValueTextEquals(PackageTypePropertyName)) - { - ReadPackageTypes(packageSpec, ref jsonReader); - } - else if (jsonReader.ValueTextEquals(ProjectUrlPropertyName)) - { - packageSpec.ProjectUrl = jsonReader.ReadNextTokenAsString(); - } - else if (jsonReader.ValueTextEquals(ReleaseNotesPropertyName)) - { - packageSpec.ReleaseNotes = jsonReader.ReadNextTokenAsString(); - } - else if (jsonReader.ValueTextEquals(RequireLicenseAcceptancePropertyName)) - { - packageSpec.RequireLicenseAcceptance = jsonReader.ReadNextTokenAsBoolOrFalse(); - } - else if (jsonReader.ValueTextEquals(SummaryPropertyName)) - { - packageSpec.Summary = jsonReader.ReadNextTokenAsString(); - } - else if (jsonReader.ValueTextEquals(TagsPropertyName)) - { - jsonReader.Read(); - string[] tags = jsonReader.ReadStringArrayAsIList()?.ToArray(); - - if (tags != null) - { - packageSpec.Tags = tags; - } - } - else - { - jsonReader.Skip(); - } - } - } - isMappingsNull = isPackOptionsValueAnObject && !wasMappingsRead; - } - - [Obsolete] - private static bool ReadPackOptionsFiles(PackageSpec packageSpec, ref Utf8JsonStreamReader jsonReader, bool wasMappingsRead) - { - IReadOnlyList excludeFiles = null; - IReadOnlyList exclude = null; - IReadOnlyList includeFiles = null; - IReadOnlyList include = null; - - if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) - { - while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) - { - if (jsonReader.ValueTextEquals(ExcludeFilesPropertyName)) - { - excludeFiles = jsonReader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); - } - else if (jsonReader.ValueTextEquals(ExcludePropertyName)) - { - exclude = jsonReader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); - } - else if (jsonReader.ValueTextEquals(IncludeFilesPropertyName)) - { - includeFiles = jsonReader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); - } - else if (jsonReader.ValueTextEquals(IncludePropertyName)) - { - include = jsonReader.ReadNextStringOrArrayOfStringsAsReadOnlyList(); - } - else if (jsonReader.ValueTextEquals(MappingsPropertyName)) - { - if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) - { - while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) - { - wasMappingsRead = true; - var mappingsPropertyName = jsonReader.GetString(); - ReadMappings(ref jsonReader, mappingsPropertyName, packageSpec.PackOptions.Mappings); - } - } - } - else - { - jsonReader.Skip(); - } - } - } - - if (include != null || includeFiles != null || exclude != null || excludeFiles != null) - { - packageSpec.PackOptions.IncludeExcludeFiles = new IncludeExcludeFiles() - { - ExcludeFiles = excludeFiles, - Exclude = exclude, - IncludeFiles = includeFiles, - Include = include - }; - } - - return wasMappingsRead; - } - private static RuntimeDependencySet ReadRuntimeDependencySet(ref Utf8JsonStreamReader jsonReader, string dependencySetName) { List dependencies = null; @@ -1659,43 +1261,6 @@ private static List ReadRuntimes(ref Utf8JsonStreamReader js return runtimeDescriptions; } - [Obsolete] - private static void ReadScripts(ref Utf8JsonStreamReader jsonReader, PackageSpec packageSpec) - { - if (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.StartObject) - { - while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.PropertyName) - { - var propertyName = jsonReader.GetString(); - if (jsonReader.Read()) - { - if (jsonReader.TokenType == JsonTokenType.String) - { - packageSpec.Scripts[propertyName] = new string[] { jsonReader.GetString() }; - } - else if (jsonReader.TokenType == JsonTokenType.StartArray) - { - IList list = null; - - while (jsonReader.Read() && jsonReader.TokenType == JsonTokenType.String) - { - list ??= []; - list.Add(jsonReader.GetString()); - } - - packageSpec.Scripts[propertyName] = list ?? Enumerable.Empty(); - } - else - { - throw FileFormatException.Create( - string.Format(CultureInfo.CurrentCulture, "The value of a script in '{0}' can only be a string or an array of strings", PackageSpec.PackageSpecFileName), - packageSpec.FilePath); - } - } - } - } - } - private static List ReadSupports(ref Utf8JsonStreamReader jsonReader) { List compatibilityProfiles = null; diff --git a/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.cs b/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.cs index 352e8083132..54b79772540 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.cs +++ b/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.cs @@ -103,8 +103,6 @@ internal static PackageSpec GetPackageSpec(JsonTextReader jsonReader, string nam List compatibilityProfiles = null; List runtimeDescriptions = null; - var wasPackOptionsSet = false; - var isMappingsNull = false; string filePath = name == null ? null : Path.GetFullPath(packageSpecPath); @@ -117,29 +115,6 @@ internal static PackageSpec GetPackageSpec(JsonTextReader jsonReader, string nam switch (propertyName) { -#pragma warning disable CS0612 // Type or member is obsolete - case "authors": - packageSpec.Authors = ReadStringArray(jsonReader) ?? Array.Empty(); - break; - - case "buildOptions": - ReadBuildOptions(jsonReader, packageSpec); - break; - - case "contentFiles": - List contentFiles = jsonReader.ReadStringArrayAsList(); - - if (contentFiles != null) - { - packageSpec.ContentFiles = contentFiles; - } - break; - - case "copyright": - packageSpec.Copyright = jsonReader.ReadNextTokenAsString(); - break; -#pragma warning restore CS0612 // Type or member is obsolete - case "dependencies": ReadDependencies( jsonReader, @@ -148,31 +123,10 @@ internal static PackageSpec GetPackageSpec(JsonTextReader jsonReader, string nam isGacOrFrameworkReference: false); break; -#pragma warning disable CS0612 // Type or member is obsolete - case "description": - packageSpec.Description = jsonReader.ReadNextTokenAsString(); - break; -#pragma warning restore CS0612 // Type or member is obsolete - case "frameworks": ReadFrameworks(jsonReader, packageSpec); break; -#pragma warning disable CS0612 // Type or member is obsolete - case "language": - packageSpec.Language = jsonReader.ReadNextTokenAsString(); - break; - - case "packInclude": - ReadPackInclude(jsonReader, packageSpec); - break; - - case "packOptions": - ReadPackOptions(jsonReader, packageSpec, ref isMappingsNull); - wasPackOptionsSet = true; - break; -#pragma warning restore CS0612 // Type or member is obsolete - case "restore": ReadMSBuildMetadata(jsonReader, packageSpec, environmentVariableReader); break; @@ -181,20 +135,10 @@ internal static PackageSpec GetPackageSpec(JsonTextReader jsonReader, string nam runtimeDescriptions = ReadRuntimes(jsonReader); break; -#pragma warning disable CS0612 // Type or member is obsolete - case "scripts": - ReadScripts(jsonReader, packageSpec); - break; -#pragma warning restore CS0612 // Type or member is obsolete - case "supports": compatibilityProfiles = ReadSupports(jsonReader); break; - case "title": - packageSpec.Title = jsonReader.ReadNextTokenAsString(); - break; - case "version": string version = jsonReader.ReadAsString(); @@ -202,9 +146,6 @@ internal static PackageSpec GetPackageSpec(JsonTextReader jsonReader, string nam { try { -#pragma warning disable CS0612 // Type or member is obsolete - packageSpec.HasVersionSnapshot = PackageSpecUtility.IsSnapshotVersion(version); -#pragma warning restore CS0612 // Type or member is obsolete packageSpec.Version = PackageSpecUtility.SpecifySnapshot(version, snapshotValue); } catch (Exception ex) @@ -219,23 +160,6 @@ internal static PackageSpec GetPackageSpec(JsonTextReader jsonReader, string nam packageSpec.Name = name; packageSpec.FilePath = name == null ? null : Path.GetFullPath(packageSpecPath); -#pragma warning disable CS0612 // Type or member is obsolete - if (!wasPackOptionsSet) - { - packageSpec.Owners = Array.Empty(); - packageSpec.PackOptions = new PackOptions() - { - PackageType = Array.Empty() - }; - packageSpec.Tags = Array.Empty(); - } - - if (isMappingsNull) - { - packageSpec.PackOptions.Mappings = null; - } -#pragma warning restore CS0612 // Type or member is obsolete - packageSpec.RuntimeGraph = new RuntimeGraph( runtimeDescriptions ?? Enumerable.Empty(), compatibilityProfiles ?? Enumerable.Empty()); @@ -263,20 +187,6 @@ private static PackageType CreatePackageType(JsonTextReader jsonReader) return new PackageType(name, Packaging.Core.PackageType.EmptyVersion); } - [Obsolete] - private static void ReadBuildOptions(JsonTextReader jsonReader, PackageSpec packageSpec) - { - packageSpec.BuildOptions = new BuildOptions(); - - jsonReader.ReadObject(buildOptionsPropertyName => - { - if (buildOptionsPropertyName == "outputName") - { - packageSpec.BuildOptions.OutputName = jsonReader.ReadNextTokenAsString(); - } - }); - } - [Obsolete] private static void ReadCentralPackageVersions( JsonTextReader jsonReader, @@ -871,7 +781,7 @@ private static void ReadImports(PackageSpec packageSpec, JsonTextReader jsonRead CultureInfo.CurrentCulture, Strings.Log_InvalidImportFramework, import, - PackageSpec.PackageSpecFileName), + packageSpec.FilePath), lineNumber, linePosition, packageSpec.FilePath); @@ -882,84 +792,6 @@ private static void ReadImports(PackageSpec packageSpec, JsonTextReader jsonRead } } - [Obsolete] - private static void ReadMappings(JsonTextReader jsonReader, string mappingKey, IDictionary mappings) - { - if (jsonReader.ReadNextToken()) - { - switch (jsonReader.TokenType) - { - case JsonToken.String: - { - var files = new IncludeExcludeFiles() - { - Include = new[] { (string)jsonReader.Value } - }; - - mappings.Add(mappingKey, files); - } - break; - - case JsonToken.StartArray: - { - IReadOnlyList include = jsonReader.ReadStringArrayAsReadOnlyListFromArrayStart(); - - var files = new IncludeExcludeFiles() - { - Include = include - }; - - mappings.Add(mappingKey, files); - } - break; - - case JsonToken.StartObject: - { - IReadOnlyList excludeFiles = null; - IReadOnlyList exclude = null; - IReadOnlyList includeFiles = null; - IReadOnlyList include = null; - - jsonReader.ReadProperties(filesPropertyName => - { - switch (filesPropertyName) - { - case "excludeFiles": - excludeFiles = jsonReader.ReadStringOrArrayOfStringsAsReadOnlyList(); - break; - - case "exclude": - exclude = jsonReader.ReadStringOrArrayOfStringsAsReadOnlyList(); - break; - - case "includeFiles": - includeFiles = jsonReader.ReadStringOrArrayOfStringsAsReadOnlyList(); - break; - - case "include": - include = jsonReader.ReadStringOrArrayOfStringsAsReadOnlyList(); - break; - } - }); - - if (include != null || includeFiles != null || exclude != null || excludeFiles != null) - { - var files = new IncludeExcludeFiles() - { - ExcludeFiles = excludeFiles, - Exclude = exclude, - IncludeFiles = includeFiles, - Include = include - }; - - mappings.Add(mappingKey, files); - } - } - break; - } - } - } - [Obsolete] private static void ReadMSBuildMetadata(JsonTextReader jsonReader, PackageSpec packageSpec, IEnvironmentVariableReader environmentVariableReader) { @@ -1410,211 +1242,6 @@ private static ImmutableArray ReadNuGetLogCodesList(JsonTextReader return retVal; } - [Obsolete] - private static void ReadPackageTypes(PackageSpec packageSpec, JsonTextReader jsonReader) - { - var errorLine = 0; - var errorColumn = 0; - - IReadOnlyList packageTypes = null; - PackageType packageType = null; - - try - { - if (jsonReader.ReadNextToken()) - { - errorLine = jsonReader.LineNumber; - errorColumn = jsonReader.LinePosition; - - switch (jsonReader.TokenType) - { - case JsonToken.String: - packageType = CreatePackageType(jsonReader); - - packageTypes = new[] { packageType }; - break; - - case JsonToken.StartArray: - var types = new List(); - - while (jsonReader.ReadNextToken() && jsonReader.TokenType != JsonToken.EndArray) - { - if (jsonReader.TokenType != JsonToken.String) - { - throw FileFormatException.Create( - string.Format( - CultureInfo.CurrentCulture, - Strings.InvalidPackageType, - PackageSpec.PackageSpecFileName), - errorLine, - errorColumn, - packageSpec.FilePath); - } - - packageType = CreatePackageType(jsonReader); - - types.Add(packageType); - } - - packageTypes = types; - break; - - case JsonToken.Null: - break; - - default: - throw new InvalidCastException(); - } - -#pragma warning disable CS0612 // Type or member is obsolete - if (packageTypes != null) - { - packageSpec.PackOptions.PackageType = packageTypes; - } -#pragma warning restore CS0612 // Type or member is obsolete - } - } - catch (Exception) - { - throw FileFormatException.Create( - string.Format( - CultureInfo.CurrentCulture, - Strings.InvalidPackageType, - PackageSpec.PackageSpecFileName), - errorLine, - errorColumn, - packageSpec.FilePath); - } - } - - [Obsolete] - private static void ReadPackInclude(JsonTextReader jsonReader, PackageSpec packageSpec) - { - jsonReader.ReadObject(propertyName => - { - string propertyValue = jsonReader.ReadAsString(); - - packageSpec.PackInclude.Add(new KeyValuePair(propertyName, propertyValue)); - }); - } - - [Obsolete] - private static void ReadPackOptions(JsonTextReader jsonReader, PackageSpec packageSpec, ref bool isMappingsNull) - { - var wasMappingsRead = false; - - bool isPackOptionsValueAnObject = jsonReader.ReadObject(propertyName => - { - switch (propertyName) - { - case "files": - wasMappingsRead = ReadPackOptionsFiles(packageSpec, jsonReader, wasMappingsRead); - break; - - case "iconUrl": - packageSpec.IconUrl = jsonReader.ReadNextTokenAsString(); - break; - - case "licenseUrl": - packageSpec.LicenseUrl = jsonReader.ReadNextTokenAsString(); - break; - - case "owners": - string[] owners = ReadStringArray(jsonReader); - - if (owners != null) - { - packageSpec.Owners = owners; - } - break; - - case "packageType": - ReadPackageTypes(packageSpec, jsonReader); - break; - - case "projectUrl": - packageSpec.ProjectUrl = jsonReader.ReadNextTokenAsString(); - break; - - case "releaseNotes": - packageSpec.ReleaseNotes = jsonReader.ReadNextTokenAsString(); - break; - - case "requireLicenseAcceptance": - packageSpec.RequireLicenseAcceptance = ReadNextTokenAsBoolOrFalse(jsonReader, packageSpec.FilePath); - break; - - case "summary": - packageSpec.Summary = jsonReader.ReadNextTokenAsString(); - break; - - case "tags": - string[] tags = ReadStringArray(jsonReader); - - if (tags != null) - { - packageSpec.Tags = tags; - } - break; - } - }); - - isMappingsNull = isPackOptionsValueAnObject && !wasMappingsRead; - } - - [Obsolete] - private static bool ReadPackOptionsFiles(PackageSpec packageSpec, JsonTextReader jsonReader, bool wasMappingsRead) - { - IReadOnlyList excludeFiles = null; - IReadOnlyList exclude = null; - IReadOnlyList includeFiles = null; - IReadOnlyList include = null; - - jsonReader.ReadObject(filesPropertyName => - { - switch (filesPropertyName) - { - case "excludeFiles": - excludeFiles = jsonReader.ReadStringOrArrayOfStringsAsReadOnlyList(); - break; - - case "exclude": - exclude = jsonReader.ReadStringOrArrayOfStringsAsReadOnlyList(); - break; - - case "includeFiles": - includeFiles = jsonReader.ReadStringOrArrayOfStringsAsReadOnlyList(); - break; - - case "include": - include = jsonReader.ReadStringOrArrayOfStringsAsReadOnlyList(); - break; - - case "mappings": - jsonReader.ReadObject(mappingsPropertyName => - { - wasMappingsRead = true; - - ReadMappings(jsonReader, mappingsPropertyName, packageSpec.PackOptions.Mappings); - }); - break; - } - }); - - if (include != null || includeFiles != null || exclude != null || excludeFiles != null) - { - packageSpec.PackOptions.IncludeExcludeFiles = new IncludeExcludeFiles() - { - ExcludeFiles = excludeFiles, - Exclude = exclude, - IncludeFiles = includeFiles, - Include = include - }; - } - - return wasMappingsRead; - } - [Obsolete] static RuntimeDependencySet ReadRuntimeDependencySet(JsonTextReader jsonReader, string dependencySetName) { @@ -1677,48 +1304,6 @@ private static List ReadRuntimes(JsonTextReader jsonReader) return runtimeDescriptions; } - [Obsolete] - private static void ReadScripts(JsonTextReader jsonReader, PackageSpec packageSpec) - { - jsonReader.ReadObject(propertyName => - { - if (jsonReader.ReadNextToken()) - { - if (jsonReader.TokenType == JsonToken.String) - { - packageSpec.Scripts[propertyName] = new string[] { (string)jsonReader.Value }; - } - else if (jsonReader.TokenType == JsonToken.StartArray) - { - var list = new List(); - - while (jsonReader.ReadNextToken() && jsonReader.TokenType == JsonToken.String) - { - list.Add((string)jsonReader.Value); - } - - packageSpec.Scripts[propertyName] = list; - } - else - { - throw FileFormatException.Create( - string.Format(CultureInfo.CurrentCulture, "The value of a script in '{0}' can only be a string or an array of strings", PackageSpec.PackageSpecFileName), - jsonReader.LineNumber, - jsonReader.LinePosition, - packageSpec.FilePath); - } - } - }); - } - - [Obsolete] - private static string[] ReadStringArray(JsonTextReader jsonReader) - { - List list = jsonReader.ReadStringArrayAsList(); - - return list?.ToArray(); - } - [Obsolete] private static List ReadSupports(JsonTextReader jsonReader) { diff --git a/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/PackOptions.cs b/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/PackOptions.cs deleted file mode 100644 index e71a3a01173..00000000000 --- a/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/PackOptions.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using NuGet.Packaging.Core; -using NuGet.Shared; - -namespace NuGet.ProjectModel -{ - public class PackOptions : IEquatable - { - public IReadOnlyList PackageType { get; set; } = new List(); - public IncludeExcludeFiles IncludeExcludeFiles { get; set; } - public IDictionary Mappings { get; set; } = new Dictionary(); - - public override int GetHashCode() - { - var hashCode = new HashCodeCombiner(); - - hashCode.AddSequence(PackageType); - hashCode.AddObject(IncludeExcludeFiles); - hashCode.AddDictionary(Mappings); - - return hashCode.CombinedHash; - } - - public override bool Equals(object obj) - { - return Equals(obj as PackOptions); - } - - public bool Equals(PackOptions other) - { - if (other == null) - { - return false; - } - - if (ReferenceEquals(this, other)) - { - return true; - } - - return PackageType.SequenceEqualWithNullCheck(other.PackageType) && - Mappings.SequenceEqualWithNullCheck(other.Mappings) && - EqualityUtility.EqualsWithNullCheck(IncludeExcludeFiles, other.IncludeExcludeFiles); - } - public PackOptions Clone() - { - var clonedObject = new PackOptions(); - clonedObject.PackageType = new List(PackageType); - clonedObject.IncludeExcludeFiles = IncludeExcludeFiles?.Clone(); - if (Mappings != null) - { - clonedObject.Mappings = new Dictionary(); - foreach (var kvp in Mappings) - { - clonedObject.Mappings.Add(kvp.Key, kvp.Value.Clone()); - } - } - return clonedObject; - } - } -} diff --git a/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/PackageSpec.cs b/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/PackageSpec.cs index ea9fe1909d3..004acce560b 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/PackageSpec.cs +++ b/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/PackageSpec.cs @@ -19,7 +19,6 @@ namespace NuGet.ProjectModel [DebuggerDisplay("{Name}")] public class PackageSpec { - public static readonly string PackageSpecFileName = "project.json"; public static readonly NuGetVersion DefaultVersion = new NuGetVersion(1, 0, 0); public PackageSpec(IList frameworks) @@ -35,29 +34,13 @@ internal PackageSpec( IList frameworks, IList dependencies, RuntimeGraph runtimeGraph, - ProjectRestoreSettings restoreSettings, - string[] authors = null, - string[] owners = null, - string[] tags = null, - IList contentFiles = null, - IDictionary> scripts = null, - IDictionary packInclude = null, - PackOptions packOptions = null + ProjectRestoreSettings restoreSettings ) { TargetFrameworks = frameworks; Dependencies = dependencies ?? new List(); RuntimeGraph = runtimeGraph ?? RuntimeGraph.Empty; RestoreSettings = restoreSettings ?? new ProjectRestoreSettings(); -#pragma warning disable CS0612 // Type or member is obsolete - Authors = authors ?? Array.Empty(); - Owners = owners ?? Array.Empty(); - Tags = tags ?? Array.Empty(); - ContentFiles = contentFiles ?? new List(); - Scripts = scripts ?? new Dictionary>(StringComparer.OrdinalIgnoreCase); - PackInclude = packInclude ?? new Dictionary(); - PackOptions = packOptions ?? new PackOptions(); -#pragma warning restore CS0612 // Type or member is obsolete } public string FilePath { get; set; } @@ -66,8 +49,6 @@ internal PackageSpec( public string Name { get; set; } - public string Title { get; set; } - private NuGetVersion _version = DefaultVersion; public NuGetVersion Version { @@ -75,68 +56,11 @@ public NuGetVersion Version set { _version = value; -#pragma warning disable CS0612 // Type or member is obsolete IsDefaultVersion = false; -#pragma warning restore CS0612 // Type or member is obsolete } } - [Obsolete] - public bool IsDefaultVersion { get; set; } = true; - - [Obsolete] - public bool HasVersionSnapshot { get; set; } - - [Obsolete] - public string Description { get; set; } - - [Obsolete] - public string Summary { get; set; } - - [Obsolete] - public string ReleaseNotes { get; set; } - - [Obsolete] - public string[] Authors { get; set; } - - [Obsolete] - public string[] Owners { get; set; } - - [Obsolete] - public string ProjectUrl { get; set; } - - [Obsolete] - public string IconUrl { get; set; } - - [Obsolete] - public string LicenseUrl { get; set; } - - [Obsolete] - public bool RequireLicenseAcceptance { get; set; } - - [Obsolete] - public string Copyright { get; set; } - - [Obsolete] - public string Language { get; set; } - - [Obsolete] - public BuildOptions BuildOptions { get; set; } - - [Obsolete] - public string[] Tags { get; set; } - - [Obsolete] - public IList ContentFiles { get; set; } - - [Obsolete] - public IDictionary> Scripts { get; private set; } - - [Obsolete] - public IDictionary PackInclude { get; private set; } - - [Obsolete] - public PackOptions PackOptions { get; set; } + public bool IsDefaultVersion { get; private set; } = true; /// /// List of dependencies that apply to all frameworks. @@ -166,29 +90,8 @@ public override int GetHashCode() { var hashCode = new HashCodeCombiner(); - hashCode.AddObject(Title); hashCode.AddObject(Version); -#pragma warning disable CS0612 // Type or member is obsolete hashCode.AddObject(IsDefaultVersion); - hashCode.AddObject(HasVersionSnapshot); - hashCode.AddObject(Description); - hashCode.AddObject(Summary); - hashCode.AddObject(ReleaseNotes); - hashCode.AddSequence(Authors); - hashCode.AddSequence(Owners); - hashCode.AddObject(ProjectUrl); - hashCode.AddObject(IconUrl); - hashCode.AddObject(LicenseUrl); - hashCode.AddObject(RequireLicenseAcceptance); - hashCode.AddObject(Copyright); - hashCode.AddObject(Language); - hashCode.AddObject(BuildOptions); - hashCode.AddSequence(Tags); - hashCode.AddSequence(ContentFiles); - hashCode.AddDictionary(Scripts); - hashCode.AddDictionary(PackInclude); - hashCode.AddObject(PackOptions); -#pragma warning restore CS0612 // Type or member is obsolete hashCode.AddSequence(Dependencies); hashCode.AddSequence(TargetFrameworks); hashCode.AddObject(RuntimeGraph); @@ -216,29 +119,8 @@ public bool Equals(PackageSpec other) // Name and FilePath are not used for comparison since they are not serialized to JSON. - return Title == other.Title && - EqualityUtility.EqualsWithNullCheck(Version, other.Version) && -#pragma warning disable CS0612 // Type or member is obsolete + return EqualityUtility.EqualsWithNullCheck(Version, other.Version) && IsDefaultVersion == other.IsDefaultVersion && - HasVersionSnapshot == other.HasVersionSnapshot && - Description == other.Description && - Summary == other.Summary && - ReleaseNotes == other.ReleaseNotes && - EqualityUtility.SequenceEqualWithNullCheck(Authors, other.Authors) && - EqualityUtility.SequenceEqualWithNullCheck(Owners, other.Owners) && - ProjectUrl == other.ProjectUrl && - IconUrl == other.IconUrl && - LicenseUrl == other.LicenseUrl && - RequireLicenseAcceptance == other.RequireLicenseAcceptance && - Copyright == other.Copyright && - Language == other.Language && - EqualityUtility.EqualsWithNullCheck(BuildOptions, other.BuildOptions) && - EqualityUtility.SequenceEqualWithNullCheck(Tags, other.Tags) && - EqualityUtility.SequenceEqualWithNullCheck(ContentFiles, other.ContentFiles) && - EqualityUtility.DictionaryOfSequenceEquals(Scripts, other.Scripts) && - EqualityUtility.DictionaryEquals(PackInclude, other.PackInclude, (s, o) => StringComparer.Ordinal.Equals(s, o)) && - EqualityUtility.EqualsWithNullCheck(PackOptions, other.PackOptions) && -#pragma warning restore CS0612 // Type or member is obsolete EqualityUtility.OrderedEquals(Dependencies, other.Dependencies, dep => dep.Name, StringComparer.OrdinalIgnoreCase) && EqualityUtility.OrderedEquals(TargetFrameworks, other.TargetFrameworks, tfm => tfm.TargetAlias, StringComparer.OrdinalIgnoreCase) && EqualityUtility.EqualsWithNullCheck(RuntimeGraph, other.RuntimeGraph) && @@ -257,60 +139,22 @@ public PackageSpec Clone() } else { - targetFrameworks = new List(TargetFrameworks.Count); - targetFrameworks.AddRange(TargetFrameworks); + targetFrameworks = [.. TargetFrameworks]; } return new PackageSpec( targetFrameworks, Dependencies?.ToList(), RuntimeGraph?.Clone(), - RestoreSettings?.Clone(), -#pragma warning disable CS0612 // Type or member is obsolete - (string[])Authors?.Clone(), - (string[])Owners?.Clone(), - (string[])Tags?.Clone(), - ContentFiles != null ? new List(ContentFiles) : null, - CloneScripts(Scripts), - PackInclude != null ? new Dictionary(PackInclude) : null, - PackOptions?.Clone() -#pragma warning restore CS0612 // Type or member is obsolete + RestoreSettings?.Clone() ) { Name = Name, FilePath = FilePath, - Title = Title, -#pragma warning disable CS0612 // Type or member is obsolete - HasVersionSnapshot = HasVersionSnapshot, - Description = Description, - Summary = Summary, - ReleaseNotes = ReleaseNotes, - ProjectUrl = ProjectUrl, - IconUrl = IconUrl, - LicenseUrl = LicenseUrl, - RequireLicenseAcceptance = RequireLicenseAcceptance, - Language = Language, - Copyright = Copyright, Version = Version, IsDefaultVersion = IsDefaultVersion, - BuildOptions = BuildOptions?.Clone(), -#pragma warning restore CS0612 // Type or member is obsolete RestoreMetadata = RestoreMetadata?.Clone() }; } - - private IDictionary> CloneScripts(IDictionary> toBeCloned) - { - if (toBeCloned != null) - { - var clone = new Dictionary>(toBeCloned.Count); - foreach (var kvp in toBeCloned) - { - clone.Add(kvp.Key, new List(kvp.Value)); - } - return clone; - } - return null; - } } } diff --git a/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/PackageSpecWriter.cs b/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/PackageSpecWriter.cs index c1880c0a110..ac3c8cc8f29 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/PackageSpecWriter.cs +++ b/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/PackageSpecWriter.cs @@ -44,26 +44,12 @@ internal static void Write(PackageSpec packageSpec, IObjectWriter writer, bool h throw new ArgumentNullException(nameof(writer)); } - SetValue(writer, "title", packageSpec.Title); - -#pragma warning disable CS0612 // Type or member is obsolete if (!packageSpec.IsDefaultVersion) { SetValue(writer, "version", packageSpec.Version?.ToFullString()); } - SetValue(writer, "description", packageSpec.Description); - SetArrayValue(writer, "authors", packageSpec.Authors); - SetValue(writer, "copyright", packageSpec.Copyright); - SetValue(writer, "language", packageSpec.Language); - SetArrayValue(writer, "contentFiles", packageSpec.ContentFiles); - SetDictionaryValue(writer, "packInclude", packageSpec.PackInclude); - SetPackOptions(writer, packageSpec); -#pragma warning restore CS0612 // Type or member is obsolete SetMSBuildMetadata(writer, packageSpec, environmentVariableReader); -#pragma warning disable CS0612 // Type or member is obsolete - SetDictionaryValues(writer, "scripts", packageSpec.Scripts); -#pragma warning restore CS0612 // Type or member is obsolete if (packageSpec.Dependencies.Count > 0) { @@ -392,53 +378,6 @@ private static void SetWarningProperties(IObjectWriter writer, ProjectRestoreMet } } - [Obsolete] - private static void SetPackOptions(IObjectWriter writer, PackageSpec packageSpec) - { - var packOptions = packageSpec.PackOptions; - if (packOptions == null) - { - return; - } - - if ((packageSpec.Owners == null || packageSpec.Owners.Length == 0) - && (packageSpec.Tags == null || packageSpec.Tags.Length == 0) - && packageSpec.ProjectUrl == null && packageSpec.IconUrl == null && packageSpec.Summary == null - && packageSpec.ReleaseNotes == null && packageSpec.LicenseUrl == null - && !packageSpec.RequireLicenseAcceptance - && (packOptions.PackageType == null || packOptions.PackageType.Count == 0)) - { - return; - } - - writer.WriteObjectStart(JsonPackageSpecReader.PackOptions); - - SetArrayValue(writer, "owners", packageSpec.Owners); - SetArrayValue(writer, "tags", packageSpec.Tags); - SetValue(writer, "projectUrl", packageSpec.ProjectUrl); - SetValue(writer, "iconUrl", packageSpec.IconUrl); - SetValue(writer, "summary", packageSpec.Summary); - SetValue(writer, "releaseNotes", packageSpec.ReleaseNotes); - SetValue(writer, "licenseUrl", packageSpec.LicenseUrl); - - SetValueIfTrue(writer, "requireLicenseAcceptance", packageSpec.RequireLicenseAcceptance); - - if (packOptions.PackageType != null) - { - if (packOptions.PackageType.Count == 1) - { - SetValue(writer, JsonPackageSpecReader.PackageType, packOptions.PackageType[0].Name); - } - else if (packOptions.PackageType.Count > 1) - { - var packageTypeNames = packOptions.PackageType.Select(p => p.Name); - SetArrayValue(writer, JsonPackageSpecReader.PackageType, packageTypeNames); - } - } - - writer.WriteObjectEnd(); - } - private static void SetDependencies(IObjectWriter writer, IEnumerable libraryDependencies) { SetDependencies(writer, "dependencies", libraryDependencies.Where(dependency => dependency.LibraryRange.TypeConstraint != LibraryDependencyTarget.Reference)); diff --git a/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/PublicAPI.Shipped.txt b/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/PublicAPI.Shipped.txt index 5eb0c4c11e9..e66bdc6c0b9 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/PublicAPI.Shipped.txt +++ b/src/nuget-client/src/NuGet.Core/NuGet.ProjectModel/PublicAPI.Shipped.txt @@ -10,6 +10,7 @@ NuGet.ProjectModel.AssetsLogMessage.EndLineNumber.set -> void ~NuGet.ProjectModel.AssetsLogMessage.Equals(NuGet.ProjectModel.IAssetsLogMessage other) -> bool ~NuGet.ProjectModel.AssetsLogMessage.FilePath.get -> string ~NuGet.ProjectModel.AssetsLogMessage.FilePath.set -> void +NuGet.ProjectModel.PackageSpec.IsDefaultVersion.get -> bool NuGet.ProjectModel.AssetsLogMessage.Level.get -> NuGet.Common.LogLevel ~NuGet.ProjectModel.AssetsLogMessage.LibraryId.get -> string ~NuGet.ProjectModel.AssetsLogMessage.LibraryId.set -> void @@ -29,12 +30,6 @@ NuGet.ProjectModel.BuildAction.BuildAction() -> void NuGet.ProjectModel.BuildAction.Equals(NuGet.ProjectModel.BuildAction other) -> bool NuGet.ProjectModel.BuildAction.IsKnown.get -> bool ~NuGet.ProjectModel.BuildAction.Value.get -> string -NuGet.ProjectModel.BuildOptions -NuGet.ProjectModel.BuildOptions.BuildOptions() -> void -~NuGet.ProjectModel.BuildOptions.Clone() -> NuGet.ProjectModel.BuildOptions -~NuGet.ProjectModel.BuildOptions.Equals(NuGet.ProjectModel.BuildOptions other) -> bool -~NuGet.ProjectModel.BuildOptions.OutputName.get -> string -~NuGet.ProjectModel.BuildOptions.OutputName.set -> void NuGet.ProjectModel.CacheFile ~NuGet.ProjectModel.CacheFile.CacheFile(string dgSpecHash) -> void ~NuGet.ProjectModel.CacheFile.DgSpecHash.get -> string @@ -125,19 +120,6 @@ NuGet.ProjectModel.IAssetsLogMessage.WarningLevel.get -> NuGet.Common.WarningLev NuGet.ProjectModel.IExternalProjectReferenceProvider ~NuGet.ProjectModel.IExternalProjectReferenceProvider.GetEntryPoints() -> System.Collections.Generic.IReadOnlyList ~NuGet.ProjectModel.IExternalProjectReferenceProvider.GetReferences(string entryPointPath) -> System.Collections.Generic.IReadOnlyList -NuGet.ProjectModel.IncludeExcludeFiles -~NuGet.ProjectModel.IncludeExcludeFiles.Clone() -> NuGet.ProjectModel.IncludeExcludeFiles -~NuGet.ProjectModel.IncludeExcludeFiles.Equals(NuGet.ProjectModel.IncludeExcludeFiles other) -> bool -~NuGet.ProjectModel.IncludeExcludeFiles.Exclude.get -> System.Collections.Generic.IReadOnlyList -~NuGet.ProjectModel.IncludeExcludeFiles.Exclude.set -> void -~NuGet.ProjectModel.IncludeExcludeFiles.ExcludeFiles.get -> System.Collections.Generic.IReadOnlyList -~NuGet.ProjectModel.IncludeExcludeFiles.ExcludeFiles.set -> void -~NuGet.ProjectModel.IncludeExcludeFiles.HandleIncludeExcludeFiles(Newtonsoft.Json.Linq.JObject jsonObject) -> bool -~NuGet.ProjectModel.IncludeExcludeFiles.Include.get -> System.Collections.Generic.IReadOnlyList -~NuGet.ProjectModel.IncludeExcludeFiles.Include.set -> void -NuGet.ProjectModel.IncludeExcludeFiles.IncludeExcludeFiles() -> void -~NuGet.ProjectModel.IncludeExcludeFiles.IncludeFiles.get -> System.Collections.Generic.IReadOnlyList -~NuGet.ProjectModel.IncludeExcludeFiles.IncludeFiles.set -> void NuGet.ProjectModel.JTokenExtensions NuGet.ProjectModel.JsonPackageSpecReader NuGet.ProjectModel.LockFile @@ -316,78 +298,30 @@ NuGet.ProjectModel.LockFileValidationResult ~NuGet.ProjectModel.LockFileValidationResult.InvalidReasons.get -> System.Collections.Generic.IReadOnlyList NuGet.ProjectModel.LockFileValidationResult.IsValid.get -> bool ~NuGet.ProjectModel.LockFileValidationResult.LockFileValidationResult(bool isValid, System.Collections.Generic.IReadOnlyList invalidReasons) -> void -NuGet.ProjectModel.PackOptions -~NuGet.ProjectModel.PackOptions.Clone() -> NuGet.ProjectModel.PackOptions -~NuGet.ProjectModel.PackOptions.Equals(NuGet.ProjectModel.PackOptions other) -> bool -~NuGet.ProjectModel.PackOptions.IncludeExcludeFiles.get -> NuGet.ProjectModel.IncludeExcludeFiles -~NuGet.ProjectModel.PackOptions.IncludeExcludeFiles.set -> void -~NuGet.ProjectModel.PackOptions.Mappings.get -> System.Collections.Generic.IDictionary -~NuGet.ProjectModel.PackOptions.Mappings.set -> void -NuGet.ProjectModel.PackOptions.PackOptions() -> void -~NuGet.ProjectModel.PackOptions.PackageType.get -> System.Collections.Generic.IReadOnlyList -~NuGet.ProjectModel.PackOptions.PackageType.set -> void NuGet.ProjectModel.PackageDependencyType NuGet.ProjectModel.PackageDependencyType.CentralTransitive = 3 -> NuGet.ProjectModel.PackageDependencyType NuGet.ProjectModel.PackageDependencyType.Direct = 0 -> NuGet.ProjectModel.PackageDependencyType NuGet.ProjectModel.PackageDependencyType.Project = 2 -> NuGet.ProjectModel.PackageDependencyType NuGet.ProjectModel.PackageDependencyType.Transitive = 1 -> NuGet.ProjectModel.PackageDependencyType NuGet.ProjectModel.PackageSpec -~NuGet.ProjectModel.PackageSpec.Authors.get -> string[] -~NuGet.ProjectModel.PackageSpec.Authors.set -> void ~NuGet.ProjectModel.PackageSpec.BaseDirectory.get -> string -~NuGet.ProjectModel.PackageSpec.BuildOptions.get -> NuGet.ProjectModel.BuildOptions -~NuGet.ProjectModel.PackageSpec.BuildOptions.set -> void ~NuGet.ProjectModel.PackageSpec.Clone() -> NuGet.ProjectModel.PackageSpec -~NuGet.ProjectModel.PackageSpec.ContentFiles.get -> System.Collections.Generic.IList -~NuGet.ProjectModel.PackageSpec.ContentFiles.set -> void -~NuGet.ProjectModel.PackageSpec.Copyright.get -> string -~NuGet.ProjectModel.PackageSpec.Copyright.set -> void ~NuGet.ProjectModel.PackageSpec.Dependencies.get -> System.Collections.Generic.IList ~NuGet.ProjectModel.PackageSpec.Dependencies.set -> void -~NuGet.ProjectModel.PackageSpec.Description.get -> string -~NuGet.ProjectModel.PackageSpec.Description.set -> void ~NuGet.ProjectModel.PackageSpec.Equals(NuGet.ProjectModel.PackageSpec other) -> bool ~NuGet.ProjectModel.PackageSpec.FilePath.get -> string ~NuGet.ProjectModel.PackageSpec.FilePath.set -> void -NuGet.ProjectModel.PackageSpec.HasVersionSnapshot.get -> bool -NuGet.ProjectModel.PackageSpec.HasVersionSnapshot.set -> void -~NuGet.ProjectModel.PackageSpec.IconUrl.get -> string -~NuGet.ProjectModel.PackageSpec.IconUrl.set -> void -NuGet.ProjectModel.PackageSpec.IsDefaultVersion.get -> bool -NuGet.ProjectModel.PackageSpec.IsDefaultVersion.set -> void -~NuGet.ProjectModel.PackageSpec.Language.get -> string -~NuGet.ProjectModel.PackageSpec.Language.set -> void -~NuGet.ProjectModel.PackageSpec.LicenseUrl.get -> string -~NuGet.ProjectModel.PackageSpec.LicenseUrl.set -> void ~NuGet.ProjectModel.PackageSpec.Name.get -> string ~NuGet.ProjectModel.PackageSpec.Name.set -> void -~NuGet.ProjectModel.PackageSpec.Owners.get -> string[] -~NuGet.ProjectModel.PackageSpec.Owners.set -> void -~NuGet.ProjectModel.PackageSpec.PackInclude.get -> System.Collections.Generic.IDictionary -~NuGet.ProjectModel.PackageSpec.PackOptions.get -> NuGet.ProjectModel.PackOptions -~NuGet.ProjectModel.PackageSpec.PackOptions.set -> void NuGet.ProjectModel.PackageSpec.PackageSpec() -> void ~NuGet.ProjectModel.PackageSpec.PackageSpec(System.Collections.Generic.IList frameworks) -> void -~NuGet.ProjectModel.PackageSpec.ProjectUrl.get -> string -~NuGet.ProjectModel.PackageSpec.ProjectUrl.set -> void -~NuGet.ProjectModel.PackageSpec.ReleaseNotes.get -> string -~NuGet.ProjectModel.PackageSpec.ReleaseNotes.set -> void -NuGet.ProjectModel.PackageSpec.RequireLicenseAcceptance.get -> bool -NuGet.ProjectModel.PackageSpec.RequireLicenseAcceptance.set -> void ~NuGet.ProjectModel.PackageSpec.RestoreMetadata.get -> NuGet.ProjectModel.ProjectRestoreMetadata ~NuGet.ProjectModel.PackageSpec.RestoreMetadata.set -> void ~NuGet.ProjectModel.PackageSpec.RestoreSettings.get -> NuGet.ProjectModel.ProjectRestoreSettings ~NuGet.ProjectModel.PackageSpec.RestoreSettings.set -> void ~NuGet.ProjectModel.PackageSpec.RuntimeGraph.get -> NuGet.RuntimeModel.RuntimeGraph ~NuGet.ProjectModel.PackageSpec.RuntimeGraph.set -> void -~NuGet.ProjectModel.PackageSpec.Scripts.get -> System.Collections.Generic.IDictionary> -~NuGet.ProjectModel.PackageSpec.Summary.get -> string -~NuGet.ProjectModel.PackageSpec.Summary.set -> void -~NuGet.ProjectModel.PackageSpec.Tags.get -> string[] -~NuGet.ProjectModel.PackageSpec.Tags.set -> void ~NuGet.ProjectModel.PackageSpec.TargetFrameworks.get -> System.Collections.Generic.IList -~NuGet.ProjectModel.PackageSpec.Title.get -> string -~NuGet.ProjectModel.PackageSpec.Title.set -> void ~NuGet.ProjectModel.PackageSpec.Version.get -> NuGet.Versioning.NuGetVersion ~NuGet.ProjectModel.PackageSpec.Version.set -> void NuGet.ProjectModel.PackageSpecExtensions @@ -620,8 +554,6 @@ override NuGet.ProjectModel.AssetsLogMessage.GetHashCode() -> int ~override NuGet.ProjectModel.BuildAction.Equals(object obj) -> bool override NuGet.ProjectModel.BuildAction.GetHashCode() -> int ~override NuGet.ProjectModel.BuildAction.ToString() -> string -~override NuGet.ProjectModel.BuildOptions.Equals(object obj) -> bool -override NuGet.ProjectModel.BuildOptions.GetHashCode() -> int ~override NuGet.ProjectModel.CacheFile.Equals(object obj) -> bool override NuGet.ProjectModel.CacheFile.GetHashCode() -> int ~override NuGet.ProjectModel.CentralTransitiveDependencyGroup.Equals(object obj) -> bool @@ -629,8 +561,6 @@ override NuGet.ProjectModel.CentralTransitiveDependencyGroup.GetHashCode() -> in ~override NuGet.ProjectModel.ExternalProjectReference.Equals(object obj) -> bool override NuGet.ProjectModel.ExternalProjectReference.GetHashCode() -> int ~override NuGet.ProjectModel.ExternalProjectReference.ToString() -> string -~override NuGet.ProjectModel.IncludeExcludeFiles.Equals(object obj) -> bool -override NuGet.ProjectModel.IncludeExcludeFiles.GetHashCode() -> int ~override NuGet.ProjectModel.LockFile.Equals(object obj) -> bool override NuGet.ProjectModel.LockFile.GetHashCode() -> int ~override NuGet.ProjectModel.LockFileDependency.Equals(object obj) -> bool @@ -644,8 +574,6 @@ override NuGet.ProjectModel.LockFileLibrary.GetHashCode() -> int override NuGet.ProjectModel.LockFileTarget.GetHashCode() -> int override NuGet.ProjectModel.LockFileTargetLibrary.Equals(object? obj) -> bool override NuGet.ProjectModel.LockFileTargetLibrary.GetHashCode() -> int -~override NuGet.ProjectModel.PackOptions.Equals(object obj) -> bool -override NuGet.ProjectModel.PackOptions.GetHashCode() -> int ~override NuGet.ProjectModel.PackageSpec.Equals(object obj) -> bool override NuGet.ProjectModel.PackageSpec.GetHashCode() -> int ~override NuGet.ProjectModel.PackagesConfigProjectRestoreMetadata.Clone() -> NuGet.ProjectModel.ProjectRestoreMetadata @@ -776,7 +704,6 @@ static readonly NuGet.ProjectModel.LockFileFormat.Version -> int ~static readonly NuGet.ProjectModel.LockFileRuntimeTarget.AssetTypeProperty -> string ~static readonly NuGet.ProjectModel.LockFileRuntimeTarget.RidProperty -> string ~static readonly NuGet.ProjectModel.PackageSpec.DefaultVersion -> NuGet.Versioning.NuGetVersion -~static readonly NuGet.ProjectModel.PackageSpec.PackageSpecFileName -> string ~static readonly NuGet.ProjectModel.PackagesLockFileFormat.LockFileName -> string static readonly NuGet.ProjectModel.PackagesLockFileFormat.PackagesLockFileVersion -> int static readonly NuGet.ProjectModel.PackagesLockFileFormat.Version -> int diff --git a/src/nuget-client/src/NuGet.Core/NuGet.Protocol/Resources/PackageUpdateResource.cs b/src/nuget-client/src/NuGet.Core/NuGet.Protocol/Resources/PackageUpdateResource.cs index e847466aec8..a587068a6d4 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.Protocol/Resources/PackageUpdateResource.cs +++ b/src/nuget-client/src/NuGet.Core/NuGet.Protocol/Resources/PackageUpdateResource.cs @@ -64,7 +64,18 @@ public async Task Push( SymbolPackageUpdateResourceV3 symbolPackageUpdateResource, ILogger log) { - await Push(packagePaths, symbolSource, timeoutInSecond, disableBuffering, getApiKey, getSymbolApiKey, noServiceEndpoint, skipDuplicate, symbolPackageUpdateResource, allowInsecureConnections: false, log); + await Push( + packagePaths, + symbolSource, + timeoutInSecond, + disableBuffering, + getApiKey, + getSymbolApiKey, + noServiceEndpoint, + skipDuplicate, + symbolPackageUpdateResource, + allowInsecureConnections: false, + log); } public async Task PushAsync( @@ -126,7 +137,18 @@ public async Task Push( bool allowInsecureConnections, ILogger log) { - await PushAsync(packagePaths, symbolSource, timeoutInSecond, disableBuffering, getApiKey, getSymbolApiKey, noServiceEndpoint, skipDuplicate, allowSnupkg: symbolPackageUpdateResource is not null, allowInsecureConnections, log); + await PushAsync( + packagePaths, + symbolSource, + timeoutInSecond, + disableBuffering, + getApiKey, + getSymbolApiKey, + noServiceEndpoint, + skipDuplicate, + allowSnupkg: symbolPackageUpdateResource is not null, + allowInsecureConnections, + log); } [Obsolete("Use Push method which takes multiple package paths.")] @@ -254,11 +276,21 @@ private async Task PushSymbolsPath(string packagePath, Path.GetFileName(symbolPackagePath), Strings.DefaultSymbolServer)); } - bool warnForHttpSources = true; + bool logErrorForHttpSources = true; foreach (string packageToPush in symbolsToPush) { - await PushPackageCore(symbolSource, apiKey, packageToPush, noServiceEndpoint, skipDuplicate, requestTimeout, warnForHttpSources, allowInsecureConnections, log, token); - warnForHttpSources = false; + await PushPackageCore( + symbolSource, + apiKey, + packageToPush, + noServiceEndpoint, + skipDuplicate, + requestTimeout, + logErrorForHttpSources, + allowInsecureConnections, + log, + token); + logErrorForHttpSources = false; } } } @@ -298,10 +330,20 @@ private async Task PushPackagePath(string packagePath, Strings.NoApiKeyFound, GetSourceDisplayName(source))); } - bool warnForHttpSources = true; + bool logErrorForHttpSources = true; foreach (string nupkgToPush in nupkgsToPush) { - bool packageWasPushed = await PushPackageCore(source, apiKey, nupkgToPush, noServiceEndpoint, skipDuplicate, requestTimeout, warnForHttpSources, allowInsecureConnections, log, token); + bool packageWasPushed = await PushPackageCore( + source, + apiKey, + nupkgToPush, + noServiceEndpoint, + skipDuplicate, + requestTimeout, + logErrorForHttpSources, + allowInsecureConnections, + log, + token); // Push corresponding symbols, if successful. if (packageWasPushed && !string.IsNullOrEmpty(symbolSource)) { @@ -330,9 +372,19 @@ private async Task PushPackagePath(string packagePath, } string symbolApiKey = getSymbolApiKey(symbolSource); - await PushPackageCore(symbolSource, symbolApiKey, symbolPackagePath, noServiceEndpoint, skipDuplicate, requestTimeout, warnForHttpSources, allowInsecureConnections, log, token); + await PushPackageCore( + symbolSource, + symbolApiKey, + symbolPackagePath, + noServiceEndpoint, + skipDuplicate, + requestTimeout, + logErrorForHttpSources, + allowInsecureConnections, + log, + token); } - warnForHttpSources = false; + logErrorForHttpSources = false; } } @@ -342,7 +394,7 @@ private async Task PushPackageCore(string source, bool noServiceEndpoint, bool skipDuplicate, TimeSpan requestTimeout, - bool warnForHttpSources, + bool logErrorForHttpSources, bool allowInsecureConnections, ILogger log, CancellationToken token) @@ -364,7 +416,7 @@ private async Task PushPackageCore(string source, else { wasPackagePushed = await PushPackageToServer(source, apiKey, packageToPush, noServiceEndpoint, skipDuplicate, - requestTimeout, warnForHttpSources, allowInsecureConnections, log, token); + requestTimeout, logErrorForHttpSources, allowInsecureConnections, log, token); } if (wasPackagePushed) @@ -413,7 +465,7 @@ private async Task PushPackageToServer(string source, bool noServiceEndpoint, bool skipDuplicate, TimeSpan requestTimeout, - bool warnForHttpSources, + bool logErrorForHttpSources, bool allowInsecureConnections, ILogger logger, CancellationToken token) @@ -422,9 +474,10 @@ private async Task PushPackageToServer(string source, bool useTempApiKey = IsSourceNuGetSymbolServer(source); HttpStatusCode? codeNotToThrow = ConvertSkipDuplicateParamToHttpStatusCode(skipDuplicate); bool showPushCommandPackagePushed = true; - if (warnForHttpSources && serviceEndpointUrl.Scheme == Uri.UriSchemeHttp && !allowInsecureConnections) + if (logErrorForHttpSources && serviceEndpointUrl.Scheme == Uri.UriSchemeHttp && !allowInsecureConnections) { - logger.LogWarning(string.Format(CultureInfo.CurrentCulture, Strings.Warning_HttpServerUsage, "push", serviceEndpointUrl)); + logger.LogError(string.Format(CultureInfo.CurrentCulture, Strings.Error_HttpServerUsage, "push", serviceEndpointUrl)); + return false; } if (useTempApiKey) @@ -726,7 +779,8 @@ private async Task DeletePackage(string source, { if (sourceUri.Scheme == Uri.UriSchemeHttp && !allowInsecureConnections) { - logger.LogWarning(string.Format(CultureInfo.CurrentCulture, Strings.Warning_HttpServerUsage, "delete", sourceUri)); + logger.LogError(string.Format(CultureInfo.CurrentCulture, Strings.Error_HttpServerUsage, "delete", sourceUri)); + return; } await DeletePackageFromServer(source, apiKey, packageId, packageVersion, noServiceEndpoint, logger, token); } diff --git a/src/nuget-client/src/NuGet.Core/NuGet.Protocol/Strings.Designer.cs b/src/nuget-client/src/NuGet.Core/NuGet.Protocol/Strings.Designer.cs index fa7d5605652..dc4ae742007 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.Protocol/Strings.Designer.cs +++ b/src/nuget-client/src/NuGet.Core/NuGet.Protocol/Strings.Designer.cs @@ -168,6 +168,15 @@ internal static string Error_DownloadTimeout { } } + /// + /// Looks up a localized string similar to You are running the '{0}' operation with an 'HTTP' source, '{1}'. NuGet requires HTTPS sources. To use HTTP sources, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information.. + /// + internal static string Error_HttpServerUsage { + get { + return ResourceManager.GetString("Error_HttpServerUsage", resourceCulture); + } + } + /// /// Looks up a localized string similar to The server responded with HTTP '403 Forbidden' when accessing the source '{0}'. This suggests that the server has authenticated your identity but has not permitted you to access the requested resource. Provide credentials that have permissions to view this resource.. /// @@ -1041,15 +1050,6 @@ internal static string VulnerabilityPage_UrlNotHttp { } } - /// - /// Looks up a localized string similar to You are running the '{0}' operation with an 'HTTP' source, '{1}'. Non-HTTPS access will be removed in a future version. Consider migrating to an 'HTTPS' source.. - /// - internal static string Warning_HttpServerUsage { - get { - return ResourceManager.GetString("Warning_HttpServerUsage", resourceCulture); - } - } - /// /// Looks up a localized string similar to Found symbols package '{0}', but no API key was specified for the symbol server. To save an API Key, run 'NuGet.exe setApiKey [your API key from http://www.NuGet.org]'.. /// diff --git a/src/nuget-client/src/NuGet.Core/NuGet.Protocol/Strings.resx b/src/nuget-client/src/NuGet.Core/NuGet.Protocol/Strings.resx index 11631b6be73..33b1f233d66 100644 --- a/src/nuget-client/src/NuGet.Core/NuGet.Protocol/Strings.resx +++ b/src/nuget-client/src/NuGet.Core/NuGet.Protocol/Strings.resx @@ -478,8 +478,8 @@ The "ms" should be localized to the abbreviation for milliseconds. String argument '{0}' cannot be null or empty - - You are running the '{0}' operation with an 'HTTP' source, '{1}'. Non-HTTPS access will be removed in a future version. Consider migrating to an 'HTTPS' source. + + You are running the '{0}' operation with an 'HTTP' source, '{1}'. NuGet requires HTTPS sources. To use HTTP sources, you must explicitly set 'allowInsecureConnections' to true in your NuGet.Config file. Refer to https://aka.ms/nuget-https-everywhere for more information. 0 - The command name. Ex. Push/Delete. 1 - server uri. @@ -530,4 +530,4 @@ The "s" should be localized to the abbreviation for seconds. {1} - number of vulerabilitiy files reported {2} - max count allowed - + \ No newline at end of file diff --git a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetPackCommandTest.cs b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetPackCommandTest.cs index 51e2d59c2b9..b04dbeb7a70 100644 --- a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetPackCommandTest.cs +++ b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.CommandLine.Test/NuGetPackCommandTest.cs @@ -942,120 +942,6 @@ public class Class1 } } - [SkipMonoTheory] - [InlineData(true)] - [InlineData(false)] - public void PackCommand_PclProjectWithProjectJsonAndTargetsNetStandard(bool packEnabled) - { - // This bug tests issue: https://github.com/NuGet/Home/issues/3108 - var nugetexe = Util.GetNuGetExePath(); - - using (var workingDirectory = TestDirectory.Create()) - { - var proj1Directory = Path.Combine(workingDirectory, "proj1"); - var project1Path = Path.Combine(proj1Directory, "proj1.csproj"); - var packagesDirectory = Path.Combine(proj1Directory, "packages"); - // create project 1 - Util.CreateFile( - proj1Directory, - "proj1.csproj", -@" - - Library - bin\Debug\ - - - v5.0 - - - - - - - - -"); - Util.CreateFile( - proj1Directory, - "proj1_file1.cs", -@"using System; - -namespace Proj1 -{ - public class Class1 - { - public int A { get; set; } - } -}"); - - Util.CreateFile(proj1Directory, - "project.json", - @"{ - ""supports"": {}, - ""dependencies"": { - ""Microsoft.NETCore.Portable.Compatibility"": ""1.0.1"", - ""NETStandard.Library"": ""1.6.0"" - }, - ""frameworks"": { - ""netstandard1.3"": { } - } - } - "); - - var environmentVariables = new Dictionary(); - - if (packEnabled) - { - environmentVariables.Add("NUGET_ENABLE_LEGACY_PROJECT_JSON_PACK", "true"); - } - - var t = CommandRunner.Run( - nugetexe, - proj1Directory, - $"restore {project1Path}", - environmentVariables: environmentVariables, - testOutputHelper: _testOutputHelper); - Assert.True(t.Success, t.AllOutput); - - // Act - var r = CommandRunner.Run( - nugetexe, - proj1Directory, - "pack proj1.csproj -build ", - environmentVariables: environmentVariables, - testOutputHelper: _testOutputHelper); - - // Assert - if (packEnabled) - { - Assert.True(0 == r.ExitCode, r.AllOutput); - var nupkgName = Path.Combine(proj1Directory, "proj1.0.0.0.nupkg"); - Assert.True(File.Exists(nupkgName)); - var package = new PackageArchiveReader(File.OpenRead(nupkgName)); - var files = package.GetNonPackageDefiningFiles(); - Array.Sort(files); - Assert.Equal( - new string[] - { - "lib/netstandard1.3/proj1.dll" - }, - files); - - Assert.Contains(string.Format(NuGetResources.ProjectJsonPack_Deprecated, "proj1"), r.AllOutput); - } - else - { - Assert.True(1 == r.ExitCode, r.AllOutput); - var nupkgName = Path.Combine(proj1Directory, "proj1.0.0.0.nupkg"); - Assert.False(File.Exists(nupkgName)); - - Assert.Contains( - string.Format(NuGetResources.Error_ProjectJson_Deprecated_And_Removed, "proj1", "NUGET_ENABLE_LEGACY_PROJECT_JSON_PACK"), r.Errors); - } - } - } - [Fact] public void PackCommand_WithTransformFile() { @@ -1570,123 +1456,6 @@ public void PackCommand_ReferencedProjectWithNuspecFile() } } - // Test that when creating a package from project file, a referenced project that - // has a json file is added as dependency. - [Fact] - public void PackCommand_ReferencedProjectWithJsonFile() - { - var nugetexe = Util.GetNuGetExePath(); - - using (var workingDirectory = TestDirectory.Create()) - { - // Arrange - - // create test projects. There are 7 projects, with the following - // dependency relationships: - // proj1 depends on proj2 & proj3 - // proj2 depends on proj4 & proj5 - // proj3 depends on proj5 & proj7 - // - // proj2 and proj6 have nuspec files. - CreateTestProject(workingDirectory, "proj1", - new string[] { - @"..\proj2\proj2.csproj", - @"..\proj3\proj3.csproj" - }); - CreateTestProject(workingDirectory, "proj2", - new string[] { - @"..\proj4\proj4.csproj", - @"..\proj5\proj5.csproj" - }); - CreateTestProject(workingDirectory, "proj3", - new string[] { - @"..\proj6\proj6.csproj", - @"..\proj7\proj7.csproj" - }); - CreateTestProject(workingDirectory, "proj4", null); - CreateTestProject(workingDirectory, "proj5", null); - CreateTestProject(workingDirectory, "proj6", null); - CreateTestProject(workingDirectory, "proj7", null); - Util.CreateFile( - Path.Combine(workingDirectory, "proj2"), - "project.json", - @"{ - ""version"": ""1.0.0.0"", - ""title"": ""Proj2"", - ""authors"": [ ""test"" ], - ""description"": ""Description"", - ""copyright"": ""Copyright © 2013"", - ""packOptions"": { - ""owners"": [ ""test"" ], - ""requireLicenseAcceptance"": ""false"" - }, - ""dependencies"": { - ""p1"": { - ""version"": ""1.5.11"" - } - }, -}"); - Util.CreateFile( - Path.Combine(workingDirectory, "proj6"), - "project.json", - @"{ - ""version"": ""2.0.0.0"", - ""title"": ""Proj6"", - ""authors"": [ ""test"" ], - ""description"": ""Description"", - ""copyright"": ""Copyright © 2013"", - ""packOptions"": { - ""owners"": [ ""test"" ], - ""requireLicenseAcceptance"": ""false"" - }, - ""dependencies"": { - ""p2"": { - ""version"": ""1.5.11"" - } - } -}"); - - // Act - var proj1Directory = Path.Combine(workingDirectory, "proj1"); - - var r = CommandRunner.Run( - nugetexe, - proj1Directory, - "pack proj1.csproj -build -IncludeReferencedProjects", - timeOutInMilliseconds: (int)TimeSpan.FromMinutes(4).TotalMilliseconds, - testOutputHelper: _testOutputHelper); - Assert.True(0 == r.ExitCode, r.Output + " " + r.Errors); - - Assert.Contains(string.Format(NuGetResources.ProjectJsonPack_Deprecated, "proj2"), r.Output); - Assert.Contains(string.Format(NuGetResources.ProjectJsonPack_Deprecated, "proj6"), r.Output); - - // Assert - var package = new PackageArchiveReader(File.OpenRead(Path.Combine(proj1Directory, "proj1.0.0.0.nupkg"))); - var files = package.GetNonPackageDefiningFiles(); - Array.Sort(files); - - // proj3 and proj7 are included in the package. - Assert.Equal( - new string[] - { - "lib/net472/proj1.dll", - "lib/net472/proj3.dll", - "lib/net472/proj7.dll", - }, - files); - - // proj2 and proj6 are added as dependencies. - var dependencies = package.NuspecReader.GetDependencyGroups().First().Packages.OrderBy(d => d.Id); ; - Assert.Equal( - new PackageDependency[] - { - new PackageDependency("proj2", VersionRange.Parse("1.0.0")), - new PackageDependency("proj6", VersionRange.Parse("2.0.0")) - }, - dependencies); - } - } - // Same test as PackCommand_ReferencedProjectWithNuspecFile, but with -MSBuidVersion // set to 14 [WindowsNTFact(Skip = "https://github.com/NuGet/Home/issues/9303")] @@ -1903,235 +1672,6 @@ public void PackCommand_ReferencedProjectWithNuspecFileWithMsbuild15OnMono() } } - // Same test as PackCommand_ReferencedProjectWithJsonFile, but with -MSBuidVersion - // set to 14 - [WindowsNTFact(Skip = "https://github.com/NuGet/Home/issues/9303")] - public void PackCommand_ReferencedProjectWithJsonFileWithMsbuild14() - { - var nugetexe = Util.GetNuGetExePath(); - using (var workingDirectory = TestDirectory.Create()) - { - // Arrange - - // create test projects. There are 7 projects, with the following - // dependency relationships: - // proj1 depends on proj2 & proj3 - // proj2 depends on proj4 & proj5 - // proj3 depends on proj5 & proj7 - // - // proj2 and proj6 have nuspec files. - CreateTestProject(workingDirectory, "proj1", - new string[] { - @"..\proj2\proj2.csproj", - @"..\proj3\proj3.csproj" - }); - CreateTestProject(workingDirectory, "proj2", - new string[] { - @"..\proj4\proj4.csproj", - @"..\proj5\proj5.csproj" - }); - CreateTestProject(workingDirectory, "proj3", - new string[] { - @"..\proj6\proj6.csproj", - @"..\proj7\proj7.csproj" - }); - CreateTestProject(workingDirectory, "proj4", null); - CreateTestProject(workingDirectory, "proj5", null); - CreateTestProject(workingDirectory, "proj6", null); - CreateTestProject(workingDirectory, "proj7", null); - Util.CreateFile( - Path.Combine(workingDirectory, "proj2"), - "project.json", - @"{ - ""version"": ""1.0.0.0"", - ""title"": ""Proj2"", - ""authors"": [ ""test"" ], - ""description"": ""Description"", - ""copyright"": ""Copyright © 2013"", - ""packOptions"": { - ""owners"": [ ""test"" ], - ""requireLicenseAcceptance"": ""false"" - }, - ""dependencies"": { - ""p1"": { - ""version"": ""1.5.11"" - } - }, -}"); - Util.CreateFile( - Path.Combine(workingDirectory, "proj6"), - "project.json", - @"{ - ""version"": ""2.0.0.0"", - ""title"": ""Proj6"", - ""authors"": [ ""test"" ], - ""description"": ""Description"", - ""copyright"": ""Copyright © 2013"", - ""packOptions"": { - ""owners"": [ ""test"" ], - ""requireLicenseAcceptance"": ""false"" - }, - ""dependencies"": { - ""p2"": { - ""version"": ""1.5.11"" - } - } -}"); - var version = "14"; - if (RuntimeEnvironmentHelper.IsMono && !RuntimeEnvironmentHelper.IsWindows) - { - version = "15.0"; - } - // Act - var proj1Directory = Path.Combine(workingDirectory, "proj1"); - var r = CommandRunner.Run( - nugetexe, - proj1Directory, - $@"pack proj1.csproj -build -IncludeReferencedProjects -MSBuildVersion {version}", - testOutputHelper: _testOutputHelper); - Assert.True(0 == r.ExitCode, r.Output + " " + r.Errors); - - // Assert - Assert.Contains(string.Format(NuGetResources.ProjectJsonPack_Deprecated, "proj2"), r.Output); - Assert.Contains(string.Format(NuGetResources.ProjectJsonPack_Deprecated, "proj6"), r.Output); - - var package = new PackageArchiveReader(File.OpenRead(Path.Combine(proj1Directory, "proj1.0.0.0.nupkg"))); - var files = package.GetFiles().ToArray(); - Array.Sort(files); - - // proj3 and proj7 are included in the package. - Assert.Equal( - new string[] - { - Path.Combine("lib", "net40", "proj1.dll"), - Path.Combine("lib", "net40", "proj3.dll"), - Path.Combine("lib", "net40", "proj7.dll") - }, - files); - - // proj2 and proj6 are added as dependencies. - var dependencies = package.NuspecReader.GetDependencyGroups().First().Packages.OrderBy(d => d.Id); - Assert.Equal( - new PackageDependency[] - { - new PackageDependency("proj2", VersionRange.Parse("1.0.0")), - new PackageDependency("proj6", VersionRange.Parse("2.0.0")) - }, - dependencies); - } - } - - [UnixMonoFact] - public void PackCommand_ReferencedProjectWithJsonFileWithMsbuild15OnMono() - { - var nugetexe = Util.GetNuGetExePath(); - using (var workingDirectory = TestDirectory.Create()) - { - // Arrange - - // create test projects. There are 7 projects, with the following - // dependency relationships: - // proj1 depends on proj2 & proj3 - // proj2 depends on proj4 & proj5 - // proj3 depends on proj5 & proj7 - // - // proj2 and proj6 have nuspec files. - CreateTestProject(workingDirectory, "proj1", - new string[] { - @"..\proj2\proj2.csproj", - @"..\proj3\proj3.csproj" - }); - CreateTestProject(workingDirectory, "proj2", - new string[] { - @"..\proj4\proj4.csproj", - @"..\proj5\proj5.csproj" - }); - CreateTestProject(workingDirectory, "proj3", - new string[] { - @"..\proj6\proj6.csproj", - @"..\proj7\proj7.csproj" - }); - CreateTestProject(workingDirectory, "proj4", null); - CreateTestProject(workingDirectory, "proj5", null); - CreateTestProject(workingDirectory, "proj6", null); - CreateTestProject(workingDirectory, "proj7", null); - Util.CreateFile( - Path.Combine(workingDirectory, "proj2"), - "project.json", - @"{ - ""version"": ""1.0.0.0"", - ""title"": ""Proj2"", - ""authors"": [ ""test"" ], - ""description"": ""Description"", - ""copyright"": ""Copyright © 2013"", - ""packOptions"": { - ""owners"": [ ""test"" ], - ""requireLicenseAcceptance"": ""false"" - }, - ""dependencies"": { - ""p1"": { - ""version"": ""1.5.11"" - } - }, -}"); - Util.CreateFile( - Path.Combine(workingDirectory, "proj6"), - "project.json", - @"{ - ""version"": ""2.0.0.0"", - ""title"": ""Proj6"", - ""authors"": [ ""test"" ], - ""description"": ""Description"", - ""copyright"": ""Copyright © 2013"", - ""packOptions"": { - ""owners"": [ ""test"" ], - ""requireLicenseAcceptance"": ""false"" - }, - ""dependencies"": { - ""p2"": { - ""version"": ""1.5.11"" - } - } -}"); - // Act - var proj1Directory = Path.Combine(workingDirectory, "proj1"); - var r = CommandRunner.Run( - nugetexe, - proj1Directory, - $@"pack proj1.csproj -build -IncludeReferencedProjects -MSBuildVersion 15.0", - testOutputHelper: _testOutputHelper); - Assert.True(0 == r.ExitCode, r.Output + " " + r.Errors); - - // Assert - Assert.Contains(string.Format(NuGetResources.ProjectJsonPack_Deprecated, "proj2"), r.Output); - Assert.Contains(string.Format(NuGetResources.ProjectJsonPack_Deprecated, "proj6"), r.Output); - - var package = new PackageArchiveReader(File.OpenRead(Path.Combine(proj1Directory, "proj1.0.0.0.nupkg"))); - var files = package.GetNonPackageDefiningFiles(); - Array.Sort(files); - - // proj3 and proj7 are included in the package. - Assert.Equal( - new string[] - { - Path.Combine("lib", "net472", "proj1.dll"), - Path.Combine("lib", "net472", "proj3.dll"), - Path.Combine("lib", "net472", "proj7.dll") - }, - files); - - // proj2 and proj6 are added as dependencies. - var dependencies = package.NuspecReader.GetDependencyGroups().First().Packages.OrderBy(d => d.Id); - Assert.Equal( - new PackageDependency[] - { - new PackageDependency("proj2", VersionRange.Parse("1.0.0")), - new PackageDependency("proj6", VersionRange.Parse("2.0.0")) - }, - dependencies); - } - } - // Test that when creating a package from project file, a referenced project that // has a nuspec file is added as dependency. withCustomReplacementTokens = true // adds the token $prefix$ to the referenced nuspec's id field (see Issue #3536) @@ -2339,8 +1879,6 @@ public void PackCommandRunner_WhenInformationalVersionIsInvalid_DoesNotThrow() /// /// The base directory. /// The name of the project. - /// The list of projects referenced by this project. Can be null. - /// The target framework version of the project. /// The text for the AssemblyVersion attribute. /// The text for the AssemblyFileVersion attribute. /// The text for the AssemblyInformationalVersion attribute. diff --git a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.UI.Test/Actions/UIActionEngineTests.cs b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.UI.Test/Actions/UIActionEngineTests.cs index fb703878ea7..973ad8000ac 100644 --- a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.UI.Test/Actions/UIActionEngineTests.cs +++ b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.UI.Test/Actions/UIActionEngineTests.cs @@ -24,6 +24,7 @@ using NuGet.Versioning; using NuGet.VisualStudio; using NuGet.VisualStudio.Internal.Contracts; +using NuGet.VisualStudio.Telemetry; using Xunit; using ContractsItemFilter = NuGet.VisualStudio.Internal.Contracts.ItemFilter; diff --git a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.UI.Test/UserInterfaceService/NuGetUITests.cs b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.UI.Test/UserInterfaceService/NuGetUITests.cs index 5f96a160f64..4723abc21dd 100644 --- a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.UI.Test/UserInterfaceService/NuGetUITests.cs +++ b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.UI.Test/UserInterfaceService/NuGetUITests.cs @@ -15,8 +15,8 @@ using NuGet.Packaging.Signing; using NuGet.ProjectManagement; using NuGet.Test.Utility; -using NuGet.VisualStudio; using NuGet.VisualStudio.Internal.Contracts; +using NuGet.VisualStudio.Telemetry; using StreamJsonRpc; using Xunit; using ContractsItemFilter = NuGet.VisualStudio.Internal.Contracts.ItemFilter; diff --git a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/CpsPackageReferenceProjectTests.cs b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/CpsPackageReferenceProjectTests.cs index 23401e5b4de..10d0d0e7a97 100644 --- a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/CpsPackageReferenceProjectTests.cs +++ b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/CpsPackageReferenceProjectTests.cs @@ -27,6 +27,7 @@ using NuGet.Test.Utility; using NuGet.Versioning; using NuGet.VisualStudio; +using NuGet.VisualStudio.Telemetry; using Test.Utility; using Test.Utility.VisualStudio; using Xunit; diff --git a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Services/NuGetProjectManagerServiceTests.cs b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Services/NuGetProjectManagerServiceTests.cs index 4d5b878619e..476b6e7551d 100644 --- a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Services/NuGetProjectManagerServiceTests.cs +++ b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Services/NuGetProjectManagerServiceTests.cs @@ -35,6 +35,7 @@ using NuGet.Versioning; using NuGet.VisualStudio; using NuGet.VisualStudio.Internal.Contracts; +using NuGet.VisualStudio.Telemetry; using StreamJsonRpc; using Test.Utility; using Test.Utility.VisualStudio; @@ -57,6 +58,7 @@ public sealed class NuGetProjectManagerServiceTests : MockedVSCollectionTests, I private TestVsSolutionManager _solutionManager; private NuGetProjectManagerServiceState _state; private TestDirectory _testDirectory; + private ConcurrentQueue _telemetryEvents; private readonly IVsProjectThreadingService _threadingService; private readonly TestLogger _logger; private readonly Mock _outputConsoleProviderMock; @@ -382,15 +384,6 @@ public async Task GetInstalledPackagesAsync_WhenProjectReturnsNullPackageReferen _solutionManager.NuGetProjects.Add(project); - var telemetrySession = new Mock(); - var telemetryEvents = new ConcurrentQueue(); - - telemetrySession - .Setup(x => x.PostEvent(It.IsAny())) - .Callback(x => telemetryEvents.Enqueue(x)); - - TelemetryActivity.NuGetTelemetryService = new NuGetVSTelemetryService(telemetrySession.Object); - IReadOnlyCollection packages = await _projectManager.GetInstalledPackagesAsync( new[] { projectId }, CancellationToken.None); @@ -406,7 +399,7 @@ public async Task GetInstalledPackagesAsync_WhenProjectReturnsNullPackageReferen Assert.Equal(expected.IsDevelopmentDependency, actual.IsDevelopmentDependency); Assert.Equal(expected.IsUserInstalled, actual.IsUserInstalled); - Assert.Equal(1, telemetryEvents.Count); + Assert.Equal(1, _telemetryEvents.Count); } } @@ -553,7 +546,7 @@ await PerformOperationAsync(async (projectManager) => } [Fact] - private async Task GetInstalledAndTransitivePackagesAsync_TransitiveOriginsWithLegacyPackageReferenceProject_OneTransitiveOriginAsync() + public async Task GetInstalledAndTransitivePackagesAsync_TransitiveOriginsWithLegacyPackageReferenceProject_OneTransitiveOriginAsync() { // packageA_2.15.3 -> packageB_1.0.0 -> packageC_2.1.43 @@ -627,7 +620,7 @@ await SimpleTestPackageUtility.CreateFullPackageAsync( } [Fact] - private async Task GetInstalledAndTransitivePackagesAsync_WithTransitivePackageNotRestored_NoTransitivePackageInfoAsync() + public async Task GetInstalledAndTransitivePackagesAsync_WithTransitivePackageNotRestored_NoTransitivePackageInfoAsync() { // packageA_1.0.0 -> packageB_2.0.0 @@ -696,7 +689,7 @@ await SimpleTestPackageUtility.CreateFullPackageAsync(pathContext.PackageSource, [Theory] [InlineData(true)] [InlineData(false)] - private async Task GetInstalledAndTransitivePackagesAsync_TransitiveOriginsWithLegacyPackageReferenceProject_MultipleOriginsAsync(bool useSameVersions) + public async Task GetInstalledAndTransitivePackagesAsync_TransitiveOriginsWithLegacyPackageReferenceProject_MultipleOriginsAsync(bool useSameVersions) { // case useSameversions = true // packageX_3.0.0 -> packageD_0.1.1 @@ -789,7 +782,7 @@ private async Task GetInstalledAndTransitivePackagesAsync_TransitiveOriginsWithL } [Fact] - private async Task GetInstalledAndTransitivePackagesAsync_WithCpsPackageReferenceProject_OneTransitiveReferenceAsync() + public async Task GetInstalledAndTransitivePackagesAsync_WithCpsPackageReferenceProject_OneTransitiveReferenceAsync() { // packageA_2.0.0 -> packageB_1.0.0 @@ -842,16 +835,6 @@ await SimpleTestPackageUtility.CreateFullPackageAsync( _solutionManager.NuGetProjects.Add(prProject); - // Prepare: Create telemetry - var telemetrySession = new Mock(); - var telemetryEvents = new ConcurrentQueue(); - - telemetrySession - .Setup(x => x.PostEvent(It.IsAny())) - .Callback(x => telemetryEvents.Enqueue(x)); - - TelemetryActivity.NuGetTelemetryService = new NuGetVSTelemetryService(telemetrySession.Object); - // Prepare: Force a nuget Restore var command = new RestoreCommand(request); // Force writing project.assets.json @@ -876,7 +859,7 @@ await SimpleTestPackageUtility.CreateFullPackageAsync( } [Fact] - private async Task GetInstalledAndTransitivePackagesAsync_TransitiveOriginsWithCpsPackageReferenceProjectAndMultipleCalls_SucceedsAsync() + public async Task GetInstalledAndTransitivePackagesAsync_TransitiveOriginsWithCpsPackageReferenceProjectAndMultipleCalls_SucceedsAsync() { // packageX_3.0.0 -> packageD_0.1.1 // packageA_2.0.0 -> packageB_1.0.0 -> packageC_0.0.1 @@ -945,16 +928,6 @@ private async Task GetInstalledAndTransitivePackagesAsync_TransitiveOriginsWithC _solutionManager.NuGetProjects.Add(prProject); - // Prepare: Create telemetry - var telemetrySession = new Mock(); - var telemetryEvents = new ConcurrentQueue(); - - telemetrySession - .Setup(x => x.PostEvent(It.IsAny())) - .Callback(x => telemetryEvents.Enqueue(x)); - - TelemetryActivity.NuGetTelemetryService = new NuGetVSTelemetryService(telemetrySession.Object); - // Prepare: Force a nuget Restore var command = new RestoreCommand(request); // Force writing project.assets.json @@ -1009,7 +982,7 @@ private async Task GetInstalledAndTransitivePackagesAsync_TransitiveOriginsWithC [Theory] [InlineData(true)] [InlineData(false)] - private async Task GetInstalledAndTransitivePackagesAsync_TransitiveOriginsWithCpsPackageReferenceProjectAndMultitargeting_SucceedsAsync(bool useSameVersions) + public async Task GetInstalledAndTransitivePackagesAsync_TransitiveOriginsWithCpsPackageReferenceProjectAndMultitargeting_SucceedsAsync(bool useSameVersions) { // useSameVersion = true // net5.0: @@ -1101,16 +1074,6 @@ private async Task GetInstalledAndTransitivePackagesAsync_TransitiveOriginsWithC _solutionManager.NuGetProjects.Add(prProject); - // Prepare: Create telemetry - var telemetrySession = new Mock(); - var telemetryEvents = new ConcurrentQueue(); - - telemetrySession - .Setup(x => x.PostEvent(It.IsAny())) - .Callback(x => telemetryEvents.Enqueue(x)); - - TelemetryActivity.NuGetTelemetryService = new NuGetVSTelemetryService(telemetrySession.Object); - // Prepare: Force a nuget Restore var command = new RestoreCommand(request); // Force writing project.assets.json @@ -1157,7 +1120,7 @@ private async Task GetInstalledAndTransitivePackagesAsync_TransitiveOriginsWithC } [Fact] - private async Task GetInstalledAndTransitivePackagesAsync_InvalidInput_ThrowsAsync() + public async Task GetInstalledAndTransitivePackagesAsync_InvalidInput_ThrowsAsync() { Initialize(); @@ -1183,7 +1146,7 @@ await Assert.ThrowsAsync(async () => } [Fact] - private async Task GetInstalledAndTransitivePackagesAsync_WithCancellationToken_ThrowsAsync() + public async Task GetInstalledAndTransitivePackagesAsync_WithCancellationToken_ThrowsAsync() { Initialize(); @@ -1196,7 +1159,7 @@ await Assert.ThrowsAsync(async () => } [Fact] - private async Task GetInstalledAndTransitivePackagesAsync_TransitiveOriginsWithCpsPackageReferenceProjectAndMultitargetingMultipleCalls_MergedResultsAsync() + public async Task GetInstalledAndTransitivePackagesAsync_TransitiveOriginsWithCpsPackageReferenceProjectAndMultitargetingMultipleCalls_MergedResultsAsync() { // net5.0: // packageX_3.0.0 -> packageD_0.1.1 @@ -1286,16 +1249,6 @@ private async Task GetInstalledAndTransitivePackagesAsync_TransitiveOriginsWithC _solutionManager.NuGetProjects.Add(prProject); - // Prepare: Create telemetry - var telemetrySession = new Mock(); - var telemetryEvents = new ConcurrentQueue(); - - telemetrySession - .Setup(x => x.PostEvent(It.IsAny())) - .Callback(x => telemetryEvents.Enqueue(x)); - - TelemetryActivity.NuGetTelemetryService = new NuGetVSTelemetryService(telemetrySession.Object); - // Prepare: Force a nuget Restore var command = new RestoreCommand(request); // Force writing project.assets.json @@ -1336,7 +1289,7 @@ private async Task GetInstalledAndTransitivePackagesAsync_TransitiveOriginsWithC } [Fact] - private async Task GetPackageFoldersAsync_InvalidInput_ThrowsAsync() + public async Task GetPackageFoldersAsync_InvalidInput_ThrowsAsync() { Initialize(); @@ -1352,7 +1305,7 @@ await Assert.ThrowsAsync(async () => } [Fact] - private async Task GetPackageFoldersAsync_WithCancellationToken_ThowsAsync() + public async Task GetPackageFoldersAsync_WithCancellationToken_ThowsAsync() { Initialize(); @@ -1365,7 +1318,7 @@ await Assert.ThrowsAsync(async () => } [Fact] - private async Task GetPackageFoldersAsync_CpsProject_ReturnsPackageFolderAsync() + public async Task GetPackageFoldersAsync_CpsProject_ReturnsPackageFolderAsync() { string projectName = Guid.NewGuid().ToString(); string projectId = projectName; @@ -1421,7 +1374,7 @@ private async Task GetPackageFoldersAsync_CpsProject_ReturnsPackageFolderAsync() } [Fact] - private async Task GetPackageFoldersAsync_LegacyProject_ReturnsPackageFolderAsync() + public async Task GetPackageFoldersAsync_LegacyProject_ReturnsPackageFolderAsync() { string projectId = Guid.NewGuid().ToString(); @@ -1466,7 +1419,7 @@ private async Task GetPackageFoldersAsync_LegacyProject_ReturnsPackageFolderAsyn } [Fact] - private async Task GetPackageFoldersAsync_LegacyProjectWithFallbackFolder_ReturnsPackageFoldersAsync() + public async Task GetPackageFoldersAsync_LegacyProjectWithFallbackFolder_ReturnsPackageFoldersAsync() { string projectId = Guid.NewGuid().ToString(); @@ -1515,7 +1468,7 @@ private async Task GetPackageFoldersAsync_LegacyProjectWithFallbackFolder_Return [Theory] [InlineData(true)] [InlineData(false)] - private async Task GetCentralPackageVersionsManagmentEnabled_SucceedsAsync(bool isCentralPackageVersionsEnabled) + public async Task GetCentralPackageVersionsManagmentEnabled_SucceedsAsync(bool isCentralPackageVersionsEnabled) { string projectName = Guid.NewGuid().ToString(); string projectId = projectName; @@ -1561,7 +1514,7 @@ private async Task GetCentralPackageVersionsManagmentEnabled_SucceedsAsync(bool } [Fact] - private async Task GetPackageFoldersAsync_CpsProjectWithFallbackFolder_ReturnsPackageFoldersAsync() + public async Task GetPackageFoldersAsync_CpsProjectWithFallbackFolder_ReturnsPackageFoldersAsync() { string projectName = Guid.NewGuid().ToString(); string projectId = projectName; @@ -1665,11 +1618,25 @@ private void Initialize(IReadOnlyList packageSources = null) _testDirectory = TestDirectory.Create(); ISettings testSettings = CreateSettings(sourceRepositoryProvider, _testDirectory); var deleteOnRestartManager = new TestDeleteOnRestartManager(); + _telemetryEvents = new ConcurrentQueue(); + + var telemetrySession = new Mock(); + + var telemetryEvents = new ConcurrentQueue(); + telemetrySession + .Setup(x => x.PostEvent(It.IsAny())) + .Callback(x => telemetryEvents.Enqueue(x)); + var telemetryService = new NuGetVSTelemetryService(telemetrySession.Object); + _packageManager = new NuGetPackageManager( sourceRepositoryProvider, testSettings, _solutionManager, - deleteOnRestartManager); + deleteOnRestartManager) + { + NuGetTelemetryService = telemetryService + }; + _state = new NuGetProjectManagerServiceState(); _sharedState = new TestSharedServiceState( new Microsoft.VisualStudio.Threading.AsyncLazy( @@ -1679,10 +1646,17 @@ private void Initialize(IReadOnlyList packageSources = null) sourceRepositoryProvider, new Microsoft.VisualStudio.Threading.AsyncLazy>( () => Task.FromResult>(sourceRepositoryProvider.GetRepositories().ToList()))); + + var telemetryProvider = new Mock(); + telemetryProvider + .Setup(x => x.EmitEvent(It.IsAny())) + .Callback(x => _telemetryEvents.Enqueue(x)); + _projectManager = new NuGetProjectManagerService( default(ServiceActivationOptions), Mock.Of(), new AuthorizationServiceClient(Mock.Of()), + telemetryProvider.Object, _state, _sharedState); } diff --git a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/ActionsTelemetryServiceTests.cs b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/ActionsTelemetryServiceTests.cs index 15e88049f67..b421026f684 100644 --- a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/ActionsTelemetryServiceTests.cs +++ b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/ActionsTelemetryServiceTests.cs @@ -6,6 +6,7 @@ using Moq; using NuGet.Common; using NuGet.VisualStudio; +using NuGet.VisualStudio.Telemetry; using Xunit; namespace NuGet.PackageManagement.VisualStudio.Test diff --git a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/NavigatedTelemetryEventTests.cs b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/NavigatedTelemetryEventTests.cs index 0bdac64b44f..dcbb43d56ce 100644 --- a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/NavigatedTelemetryEventTests.cs +++ b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/NavigatedTelemetryEventTests.cs @@ -9,6 +9,7 @@ using NuGet.PackageManagement.Telemetry; using NuGet.Versioning; using NuGet.VisualStudio; +using NuGet.VisualStudio.Telemetry; using Xunit; using ContractsItemFilter = NuGet.VisualStudio.Internal.Contracts.ItemFilter; @@ -22,7 +23,7 @@ public class NavigatedTelemetryEventTests public void Constructor_WithValidProperties_CreatedWithoutPiiData() { // Arrange - SetupTelemetryListener(); + var nuGetTelemetryService = SetupTelemetryListener(); // Arbitrary values chosen here. NavigationType navigationType = NavigationType.Hyperlink; @@ -31,7 +32,7 @@ public void Constructor_WithValidProperties_CreatedWithoutPiiData() var evt = new NavigatedTelemetryEvent(navigationType, navigationOrigin); // Act - TelemetryActivity.NuGetTelemetryService.EmitTelemetryEvent(evt); + nuGetTelemetryService.EmitTelemetryEvent(evt); // Assert Assert.NotNull(_lastTelemetryEvent); @@ -45,7 +46,7 @@ public void Constructor_WithValidProperties_CreatedWithoutPiiData() public void CreateWithExternalLink_WithValidProperties_CreatedWithoutPiiData() { // Arrange - SetupTelemetryListener(); + var nuGetTelemetryService = SetupTelemetryListener(); HyperlinkType hyperlinkTab = HyperlinkType.DeprecationAlternativeDetails; ContractsItemFilter currentTab = ContractsItemFilter.UpdatesAvailable; @@ -54,7 +55,7 @@ public void CreateWithExternalLink_WithValidProperties_CreatedWithoutPiiData() var evt = NavigatedTelemetryEvent.CreateWithExternalLink(hyperlinkTab, currentTab, isSolutionView); // Act - TelemetryActivity.NuGetTelemetryService.EmitTelemetryEvent(evt); + nuGetTelemetryService.EmitTelemetryEvent(evt); // Assert Assert.NotNull(_lastTelemetryEvent); @@ -71,7 +72,7 @@ public void CreateWithExternalLink_WithValidProperties_CreatedWithoutPiiData() public void CreateWithAddPackageSourceMapping_WithValidProperties_CreatedWithoutPiiData() { // Arrange - SetupTelemetryListener(); + var nuGetTelemetryService = SetupTelemetryListener(); int sourcesCount = 3; bool isGlobbing = false; @@ -79,7 +80,7 @@ public void CreateWithAddPackageSourceMapping_WithValidProperties_CreatedWithout var evt = NavigatedTelemetryEvent.CreateWithAddPackageSourceMapping(sourcesCount, isGlobbing); // Act - TelemetryActivity.NuGetTelemetryService.EmitTelemetryEvent(evt); + nuGetTelemetryService.EmitTelemetryEvent(evt); // Assert Assert.NotNull(_lastTelemetryEvent); @@ -97,7 +98,7 @@ public void CreateWithAddPackageSourceMapping_WithValidProperties_CreatedWithout public void CreateWithPMUIConfigurePackageSourceMapping_WithValidProperties_CreatedWithoutPiiData(PackageSourceMappingStatus packageSourceMappingStatus) { // Arrange - SetupTelemetryListener(); + var nuGetTelemetryService = SetupTelemetryListener(); ContractsItemFilter currentTab = ContractsItemFilter.UpdatesAvailable; bool isSolutionView = true; @@ -105,7 +106,7 @@ public void CreateWithPMUIConfigurePackageSourceMapping_WithValidProperties_Crea var evt = NavigatedTelemetryEvent.CreateWithPMUIConfigurePackageSourceMapping(currentTab, isSolutionView, packageSourceMappingStatus); // Act - TelemetryActivity.NuGetTelemetryService.EmitTelemetryEvent(evt); + nuGetTelemetryService.EmitTelemetryEvent(evt); // Assert Assert.NotNull(_lastTelemetryEvent); @@ -227,12 +228,12 @@ public void CreateWithAlternatePackageNavigation_CorrelatesSearchSelectionAndAct public void CreateWithClearLocalsCommand_WithValidProperties_CreatedWithoutPiiData(bool isUnifiedSettings) { // Arrange - SetupTelemetryListener(); + var nuGetTelemetryService = SetupTelemetryListener(); var evt = NavigatedTelemetryEvent.CreateWithClearLocalsCommand(isUnifiedSettings); // Act - TelemetryActivity.NuGetTelemetryService.EmitTelemetryEvent(evt); + nuGetTelemetryService.EmitTelemetryEvent(evt); // Assert Assert.NotNull(_lastTelemetryEvent); @@ -242,15 +243,15 @@ public void CreateWithClearLocalsCommand_WithValidProperties_CreatedWithoutPiiDa Assert.Equal(isUnifiedSettings, _lastTelemetryEvent[NavigatedTelemetryEvent.IsUnifiedSettingsPropertyName]); Assert.Empty(_lastTelemetryEvent.GetPiiData()); } - private Mock SetupTelemetryListener() + + private NuGetVSTelemetryService SetupTelemetryListener() { var telemetrySession = new Mock(); telemetrySession .Setup(x => x.PostEvent(It.IsAny())) .Callback(x => _lastTelemetryEvent = x); var telemetryService = new NuGetVSTelemetryService(telemetrySession.Object); - TelemetryActivity.NuGetTelemetryService = telemetryService; - return telemetrySession; + return telemetryService; } } } diff --git a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/NuGetTelemetryServiceTests.cs b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/NuGetTelemetryServiceTests.cs index bee4889f4ec..c9859f27d84 100644 --- a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/NuGetTelemetryServiceTests.cs +++ b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/NuGetTelemetryServiceTests.cs @@ -6,8 +6,8 @@ using Moq; using NuGet.Common; using NuGet.PackageManagement.Telemetry; -using NuGet.VisualStudio; using NuGet.VisualStudio.Internal.Contracts; +using NuGet.VisualStudio.Telemetry; using Xunit; namespace NuGet.PackageManagement.VisualStudio.Test diff --git a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/RestoreTelemetryServiceTests.cs b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/RestoreTelemetryServiceTests.cs index a9ecac33e00..5ab963fea73 100644 --- a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/RestoreTelemetryServiceTests.cs +++ b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/RestoreTelemetryServiceTests.cs @@ -7,6 +7,7 @@ using NuGet.Common; using NuGet.VisualStudio; using NuGet.VisualStudio.Common; +using NuGet.VisualStudio.Telemetry; using Test.Utility; using Xunit; diff --git a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/SearchSelectionTelemetryEventTests.cs b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/SearchSelectionTelemetryEventTests.cs index ac1de0dbd13..2141a5e892f 100644 --- a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/SearchSelectionTelemetryEventTests.cs +++ b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/SearchSelectionTelemetryEventTests.cs @@ -6,7 +6,7 @@ using NuGet.Common; using NuGet.PackageManagement.Telemetry; using NuGet.Versioning; -using NuGet.VisualStudio; +using NuGet.VisualStudio.Telemetry; using Xunit; namespace NuGet.PackageManagement.VisualStudio.Test diff --git a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/TelemetryOnceEmitterTests.cs b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/TelemetryOnceEmitterTests.cs index 8637a895ad6..ea1f9891d3d 100644 --- a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/TelemetryOnceEmitterTests.cs +++ b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.VisualStudio.Test/Telemetry/TelemetryOnceEmitterTests.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; using Moq; using NuGet.Common; -using NuGet.VisualStudio; +using NuGet.VisualStudio.Telemetry; using Xunit; namespace NuGet.PackageManagement.VisualStudio.Test diff --git a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.SolutionRestoreManager.Test/SolutionRestoreJobTests.cs b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.SolutionRestoreManager.Test/SolutionRestoreJobTests.cs index f9bb67f797c..2ef312564a7 100644 --- a/src/nuget-client/test/NuGet.Clients.Tests/NuGet.SolutionRestoreManager.Test/SolutionRestoreJobTests.cs +++ b/src/nuget-client/test/NuGet.Clients.Tests/NuGet.SolutionRestoreManager.Test/SolutionRestoreJobTests.cs @@ -13,6 +13,7 @@ using NuGet.PackageManagement.VisualStudio; using NuGet.Protocol.Core.Types; using NuGet.VisualStudio; +using NuGet.VisualStudio.Telemetry; using Test.Utility; using Xunit; using Task = System.Threading.Tasks.Task; @@ -46,6 +47,7 @@ public async Task Simple_ReportsNoOp_Async() var settings = Mock.Of(); var nuGetProgressReporter = Mock.Of(); var auditCheckResultCachingService = Mock.Of(); + var telemetryServiceProvider = Mock.Of(); Mock.Get(settings) .Setup(x => x.GetSection("packageRestore")) @@ -64,7 +66,8 @@ public async Task Simple_ReportsNoOp_Async() settings: settings, solutionRestoreChecker: restoreChecker, nuGetProgressReporter: nuGetProgressReporter, - auditCheckResultCachingService); + auditCheckResultCachingService, + telemetryServiceProvider); var restoreRequest = new SolutionRestoreRequest( forceRestore: true, @@ -98,6 +101,7 @@ public async Task Simple_WhenCancelled_Reports_Cancelled_Async() var settings = Mock.Of(); var nuGetProgressReporter = Mock.Of(); var auditCheckResultCachingService = Mock.Of(); + var telemetryServiceProvider = Mock.Of(); Mock.Get(settings) .Setup(x => x.GetSection("packageRestore")) @@ -116,7 +120,8 @@ public async Task Simple_WhenCancelled_Reports_Cancelled_Async() settings: settings, solutionRestoreChecker: restoreChecker, nuGetProgressReporter: nuGetProgressReporter, - auditCheckResultCachingService); + auditCheckResultCachingService, + telemetryServiceProvider); var restoreRequest = new SolutionRestoreRequest( forceRestore: true, diff --git a/src/nuget-client/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetListPackageTests.cs b/src/nuget-client/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetListPackageTests.cs index dd59781e8cf..530def96ef9 100644 --- a/src/nuget-client/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetListPackageTests.cs +++ b/src/nuget-client/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetListPackageTests.cs @@ -3,12 +3,15 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Xml.Linq; +using FluentAssertions; using Microsoft.Internal.NuGet.Testing.SignedPackages.ChildProcess; +using NuGet.Configuration; using NuGet.Packaging; using NuGet.Test.Utility; using NuGet.XPlat.FuncTest; @@ -718,50 +721,99 @@ public void DotnetListPackage_VerbositySwitchTogglesHttpVisibility(string args, } } - [PlatformTheory(Platform.Windows)] - [InlineData("true", false)] - [InlineData("false", true)] - public async Task ListPackage_WithHttpSourceAndAllowInsecureConnections_WarnsCorrectly(string allowInsecureConnections, bool isHttpWarningExpected) + [PlatformFact(Platform.Windows)] + public async Task RunDotnetListPackage_WithHttpSourceAndAllowInsecureConnections_Succeeds() { // Arrange using var pathContext = _fixture.CreateSimpleTestPathContext(); - var emptyHttpCache = new Dictionary - { - { "NUGET_HTTP_CACHE_PATH", pathContext.HttpCacheFolder }, - }; + var projectA = XPlatTestUtils.CreateProject("ProjectA", pathContext, "net472"); var packageA100 = new SimpleTestPackageContext("A", "1.0.0"); var packageA200 = new SimpleTestPackageContext("A", "2.0.0"); + await SimpleTestPackageUtility.CreatePackagesAsync(pathContext.PackageSource, packageA100, packageA200); + + using var mockServer = new FileSystemBackedV3MockServer(pathContext.PackageSource); + mockServer.Start(); + + _fixture.RunDotnetExpectSuccess(Directory.GetParent(projectA.ProjectPath).FullName, $"add package A --version 1.0.0", testOutputHelper: _testOutputHelper); + + var packageSource = new PackageSource(mockServer.ServiceIndexUri, "http-source"); + pathContext.Settings.AddSource(packageSource.Name, packageSource.Source, allowInsecureConnectionsValue: "true"); + // Act + var result = _fixture.RunDotnetExpectSuccess(Directory.GetParent(projectA.ProjectPath).FullName, $"list package --outdated", testOutputHelper: _testOutputHelper); + + // Assert + var lines = result.AllOutput.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); + lines.Should().Contain(l => l.Contains("> A 1.0.0 1.0.0 2.0.0")); + result.AllOutput.Should().NotContain(string.Format(CultureInfo.CurrentCulture, Strings.Error_HttpServerUsage, "list package", packageSource)); + } + + [PlatformFact(Platform.Windows)] + public async Task RunDotnetListPackage_WithHttpSourceWithoutAllowInsecureConnections_LogsAnError() + { + // Arrange + using var pathContext = _fixture.CreateSimpleTestPathContext(); var projectA = XPlatTestUtils.CreateProject("ProjectA", pathContext, "net472"); - await SimpleTestPackageUtility.CreatePackagesAsync( - pathContext.PackageSource, - packageA100, - packageA200); + var packageA100 = new SimpleTestPackageContext("A", "1.0.0"); + var packageA200 = new SimpleTestPackageContext("A", "2.0.0"); + await SimpleTestPackageUtility.CreatePackagesAsync(pathContext.PackageSource, packageA100, packageA200); using var mockServer = new FileSystemBackedV3MockServer(pathContext.PackageSource); mockServer.Start(); _fixture.RunDotnetExpectSuccess(Directory.GetParent(projectA.ProjectPath).FullName, $"add package A --version 1.0.0", testOutputHelper: _testOutputHelper); - pathContext.Settings.AddSource("http-source", mockServer.ServiceIndexUri, allowInsecureConnections); + var packageSource = new PackageSource(mockServer.ServiceIndexUri, "http-source"); + pathContext.Settings.AddSource(packageSource.Name, packageSource.Source, allowInsecureConnectionsValue: "false"); // Act - CommandRunnerResult listResult = _fixture.RunDotnetExpectSuccess(Directory.GetParent(projectA.ProjectPath).FullName, $"list package --outdated --no-restore", testOutputHelper: _testOutputHelper); - mockServer.Stop(); + var result = _fixture.RunDotnetExpectFailure(Directory.GetParent(projectA.ProjectPath).FullName, $"list package --outdated --no-restore", testOutputHelper: _testOutputHelper); // Assert - var lines = listResult.AllOutput.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); - Assert.True(lines.Any(l => l.Contains("> A 1.0.0 1.0.0 2.0.0")), listResult.AllOutput); - if (isHttpWarningExpected) + result.AllOutput.Should().Contain(string.Format(CultureInfo.CurrentCulture, Strings.Error_HttpServerUsage, "list package", packageSource)); + } + + [PlatformFact(Platform.Windows)] + public async Task RunDotnetListPackage_WithMultipleHttpSourcesWithoutAllowInsecureConnections_LogsAnError() + { + // Arrange + using var pathContext = _fixture.CreateSimpleTestPathContext(); + var project = XPlatTestUtils.CreateProject("ProjectA", pathContext, "net472"); + + var packageA100 = new SimpleTestPackageContext("A", "1.0.0"); + var packageA200 = new SimpleTestPackageContext("A", "2.0.0"); + await SimpleTestPackageUtility.CreatePackagesAsync(pathContext.PackageSource, packageA100, packageA200); + + using var mockServer = new FileSystemBackedV3MockServer(pathContext.PackageSource); + mockServer.Start(); + + var projectDirectory = Directory.GetParent(project.ProjectPath)!.FullName; + _fixture.RunDotnetExpectSuccess(projectDirectory, "add package A --version 1.0.0", testOutputHelper: _testOutputHelper); + + var httpSources = new[] { - Assert.Contains("warn : You are running the 'list package' operation with an 'HTTP' source", listResult.AllOutput); - } - else + new PackageSource(mockServer.ServiceIndexUri, "http-source1"), + new PackageSource(mockServer.ServiceIndexUri, "http-source2") + }; + + foreach (var source in httpSources) { - Assert.DoesNotContain("warn : You are running the 'list package' operation with an 'HTTP' source", listResult.AllOutput); + pathContext.Settings.AddSource(source.Name, source.Source, allowInsecureConnectionsValue: "false"); } + + // Act + var result = _fixture.RunDotnetExpectFailure(projectDirectory, "list package --outdated --no-restore", testOutputHelper: _testOutputHelper); + + // Assert + var expectedError = string.Format( + CultureInfo.CurrentCulture, + Strings.Error_HttpServerUsage_MultipleSources, + "list package", + Environment.NewLine + string.Join(Environment.NewLine, httpSources.Select(s => s.Name))); + + result.AllOutput.Should().Contain(expectedError); } private static string CollapseSpaces(string input) diff --git a/src/nuget-client/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetPackageSearchTests.cs b/src/nuget-client/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetPackageSearchTests.cs index 4d458b10391..67174c90080 100644 --- a/src/nuget-client/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetPackageSearchTests.cs +++ b/src/nuget-client/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetPackageSearchTests.cs @@ -33,6 +33,8 @@ public void DotnetPackageSearch_Succeed() using (var pathContext = new SimpleTestPathContext()) { // Arrange + string source = $"{_packageSearchRunnerFixture.ServerWithMultipleEndpoints.Uri}v3/index.json"; + pathContext.Settings.AddSource(source, source, allowInsecureConnectionsValue: "true"); var args = new string[] { "package", "search", "json", "--take", "10", "--prerelease", "--source", $"{_packageSearchRunnerFixture.ServerWithMultipleEndpoints.Uri}v3/index.json", "--format", "json" }; // Act diff --git a/src/nuget-client/test/NuGet.Core.FuncTests/NuGet.Commands.FuncTest/RestoreCommandTests.cs b/src/nuget-client/test/NuGet.Core.FuncTests/NuGet.Commands.FuncTest/RestoreCommandTests.cs index 0f2f58df890..e3442377df3 100644 --- a/src/nuget-client/test/NuGet.Core.FuncTests/NuGet.Commands.FuncTest/RestoreCommandTests.cs +++ b/src/nuget-client/test/NuGet.Core.FuncTests/NuGet.Commands.FuncTest/RestoreCommandTests.cs @@ -5320,8 +5320,6 @@ private static JObject BasicConfigWithNet46 } }; - json.Add("runtimes", JObject.Parse("{ \"uap10-x86\": { }, \"uap10-x86-aot\": { } }")); - return json; } } diff --git a/src/nuget-client/test/NuGet.Core.Tests/NuGet.CommandLine.Xplat.Tests/PackageSearchRunnerTests.cs b/src/nuget-client/test/NuGet.Core.Tests/NuGet.CommandLine.Xplat.Tests/PackageSearchRunnerTests.cs index 1cc88e679d4..5a4583b04db 100644 --- a/src/nuget-client/test/NuGet.Core.Tests/NuGet.CommandLine.Xplat.Tests/PackageSearchRunnerTests.cs +++ b/src/nuget-client/test/NuGet.Core.Tests/NuGet.CommandLine.Xplat.Tests/PackageSearchRunnerTests.cs @@ -4,11 +4,12 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.IO; using System.Threading; using System.Threading.Tasks; +using FluentAssertions; using NuGet.CommandLine.XPlat; using NuGet.Configuration; +using NuGet.Test.Utility; using Xunit; namespace NuGet.CommandLine.Xplat.Tests @@ -30,9 +31,12 @@ public PackageSearchRunnerTests(PackageSearchRunnerFixture fixture) public async Task RunAsync_TableFormatNormalVerbosity_OnePackageTableOutputted(int skip, int take, bool prerelease) { // Arrange + using SimpleTestPathContext pathContext = new SimpleTestPathContext(); + string source = $"{_fixture.ServerWithMultipleEndpoints.Uri}v3/index.json"; + pathContext.Settings.AddSource(source, source, allowInsecureConnectionsValue: "true"); ISettings settings = Settings.LoadDefaultSettings( - Directory.GetCurrentDirectory(), - configFileName: null, + pathContext.WorkingDirectory, + configFileName: pathContext.NuGetConfig, machineWideSettings: new XPlatMachineWideSetting()); PackageSourceProvider sourceProvider = new PackageSourceProvider(settings); var expectedDefaultColoredMessage = @@ -61,8 +65,8 @@ await PackageSearchRunner.RunAsync( cancellationToken: System.Threading.CancellationToken.None); // Assert - Assert.Equal(expectedDefaultColoredMessage, ColoredMessage[System.Console.ForegroundColor]); - Assert.Equal(expectedRedColoredMessage, ColoredMessage[ConsoleColor.Red]); + ColoredMessage[System.Console.ForegroundColor].Should().Be(expectedDefaultColoredMessage); + ColoredMessage[ConsoleColor.Red].Should().Be(expectedRedColoredMessage); } [Theory] @@ -73,10 +77,13 @@ await PackageSearchRunner.RunAsync( public async Task RunAsync_TableFormatMinimalVerbosity_OnePackageTableOutputted(int skip, int take, bool prerelease) { // Arrange + using SimpleTestPathContext pathContext = new SimpleTestPathContext(); + string source = $"{_fixture.ServerWithMultipleEndpoints.Uri}v3/index.json"; + pathContext.Settings.AddSource(source, source, allowInsecureConnectionsValue: "true"); ISettings settings = Settings.LoadDefaultSettings( - Directory.GetCurrentDirectory(), - configFileName: null, - machineWideSettings: new XPlatMachineWideSetting()); + pathContext.WorkingDirectory, + configFileName: pathContext.NuGetConfig, + machineWideSettings: new XPlatMachineWideSetting()); PackageSourceProvider sourceProvider = new PackageSourceProvider(settings); var expectedDefaultColorMessage = "| Package ID | Latest Version |" + @@ -104,9 +111,8 @@ await PackageSearchRunner.RunAsync( cancellationToken: System.Threading.CancellationToken.None); // Assert - - Assert.Equal(expectedDefaultColorMessage, ColoredMessage[System.Console.ForegroundColor]); - Assert.Equal(expectedRedColorMessage, ColoredMessage[ConsoleColor.Red]); + ColoredMessage[System.Console.ForegroundColor].Should().Be(expectedDefaultColorMessage); + ColoredMessage[ConsoleColor.Red].Should().Be(expectedRedColorMessage); } [Theory] @@ -117,10 +123,13 @@ await PackageSearchRunner.RunAsync( public async Task RunAsync_TableFormatDetailedVerbosity_OnePackageTableOutputted(int skip, int take, bool prerelease) { // Arrange + using SimpleTestPathContext pathContext = new SimpleTestPathContext(); + string source = $"{_fixture.ServerWithMultipleEndpoints.Uri}v3/index.json"; + pathContext.Settings.AddSource(source, source, allowInsecureConnectionsValue: "true"); ISettings settings = Settings.LoadDefaultSettings( - Directory.GetCurrentDirectory(), - configFileName: null, - machineWideSettings: new XPlatMachineWideSetting()); + pathContext.WorkingDirectory, + configFileName: pathContext.NuGetConfig, + machineWideSettings: new XPlatMachineWideSetting()); PackageSourceProvider sourceProvider = new PackageSourceProvider(settings); var expectedDefaultColorMessage = "| Package ID | Latest Version | Owners | Total Downloads | Vulnerable | Deprecation | Project URL | Description |" + @@ -148,9 +157,8 @@ await PackageSearchRunner.RunAsync( cancellationToken: System.Threading.CancellationToken.None); // Assert - - Assert.Equal(expectedDefaultColorMessage, ColoredMessage[System.Console.ForegroundColor]); - Assert.Equal(expectedRedColorMessage, ColoredMessage[ConsoleColor.Red]); + ColoredMessage[System.Console.ForegroundColor].Should().Be(expectedDefaultColorMessage); + ColoredMessage[ConsoleColor.Red].Should().Be(expectedRedColorMessage); } [Theory] @@ -161,10 +169,13 @@ await PackageSearchRunner.RunAsync( public async Task RunAsync_JsonFormatNormalVerbosity_OnePackageJsonOutputted(int skip, int take, bool prerelease) { // Arrange + using SimpleTestPathContext pathContext = new SimpleTestPathContext(); + string source = $"{_fixture.ServerWithMultipleEndpoints.Uri}v3/index.json"; + pathContext.Settings.AddSource(source, source, allowInsecureConnectionsValue: "true"); ISettings settings = Settings.LoadDefaultSettings( - Directory.GetCurrentDirectory(), - configFileName: null, - machineWideSettings: new XPlatMachineWideSetting()); + pathContext.WorkingDirectory, + configFileName: pathContext.NuGetConfig, + machineWideSettings: new XPlatMachineWideSetting()); PackageSourceProvider sourceProvider = new PackageSourceProvider(settings); PackageSearchArgs packageSearchArgs = new() @@ -188,7 +199,7 @@ await PackageSearchRunner.RunAsync( // Assert string message = _fixture.NormalizeNewlines(Message); - Assert.Contains(_fixture.ExpectedSearchResultNormal, message); + message.Should().Contain(_fixture.ExpectedSearchResultNormal); } [Theory] @@ -199,10 +210,13 @@ await PackageSearchRunner.RunAsync( public async Task RunAsync_JsonFormatMinimalVerbosity_OnePackageJsonOutputted(int skip, int take, bool prerelease) { // Arrange + using SimpleTestPathContext pathContext = new SimpleTestPathContext(); + string source = $"{_fixture.ServerWithMultipleEndpoints.Uri}v3/index.json"; + pathContext.Settings.AddSource(source, source, allowInsecureConnectionsValue: "true"); ISettings settings = Settings.LoadDefaultSettings( - Directory.GetCurrentDirectory(), - configFileName: null, - machineWideSettings: new XPlatMachineWideSetting()); + pathContext.WorkingDirectory, + configFileName: pathContext.NuGetConfig, + machineWideSettings: new XPlatMachineWideSetting()); PackageSourceProvider sourceProvider = new PackageSourceProvider(settings); PackageSearchArgs packageSearchArgs = new() @@ -226,7 +240,7 @@ await PackageSearchRunner.RunAsync( // Assert string message = _fixture.NormalizeNewlines(Message); - Assert.Contains(_fixture.ExpectedSearchResultMinimal, message); + message.Should().Contain(_fixture.ExpectedSearchResultMinimal); } [Theory] @@ -237,10 +251,13 @@ await PackageSearchRunner.RunAsync( public async Task RunAsync_JsonFormatDetailedVerbosity_OnePackageJsonOutputted(int skip, int take, bool prerelease) { // Arrange + using SimpleTestPathContext pathContext = new SimpleTestPathContext(); + string source = $"{_fixture.ServerWithMultipleEndpoints.Uri}v3/index.json"; + pathContext.Settings.AddSource(source, source, allowInsecureConnectionsValue: "true"); ISettings settings = Settings.LoadDefaultSettings( - Directory.GetCurrentDirectory(), - configFileName: null, - machineWideSettings: new XPlatMachineWideSetting()); + pathContext.WorkingDirectory, + configFileName: pathContext.NuGetConfig, + machineWideSettings: new XPlatMachineWideSetting()); PackageSourceProvider sourceProvider = new PackageSourceProvider(settings); PackageSearchArgs packageSearchArgs = new() @@ -264,17 +281,21 @@ await PackageSearchRunner.RunAsync( // Assert string message = _fixture.NormalizeNewlines(Message); - Assert.Contains(_fixture.ExpectedSearchResultDetailed, message); + message.Should().Contain(_fixture.ExpectedSearchResultDetailed); } [Fact] public async Task RunAsync_ExactMatchOptionEnabled_OnePackageTableOutputted() { // Arrange + using SimpleTestPathContext pathContext = new SimpleTestPathContext(); + string source = $"{_fixture.ServerWithMultipleEndpoints.Uri}v3/index.json"; + pathContext.Settings.AddSource(source, source, allowInsecureConnectionsValue: "true"); + ISettings settings = Settings.LoadDefaultSettings( - Directory.GetCurrentDirectory(), - configFileName: null, - machineWideSettings: new XPlatMachineWideSetting()); + pathContext.WorkingDirectory, + configFileName: pathContext.NuGetConfig, + machineWideSettings: new XPlatMachineWideSetting()); PackageSourceProvider sourceProvider = new PackageSourceProvider(settings); var expectedDefaultColorMessage = "| Package ID | Version | Owners | Total Downloads |" + @@ -300,19 +321,19 @@ await PackageSearchRunner.RunAsync( cancellationToken: System.Threading.CancellationToken.None); // Assert - - Assert.Equal(expectedDefaultColorMessage, ColoredMessage[System.Console.ForegroundColor]); - Assert.Equal(expectedRedColorMessage, ColoredMessage[ConsoleColor.Red]); + ColoredMessage[System.Console.ForegroundColor].Should().Be(expectedDefaultColorMessage); + ColoredMessage[ConsoleColor.Red].Should().Be(expectedRedColorMessage); } [Fact] public async Task RunAsync_WhenSourceIsInvalid_ReturnsErrorExitCode() { // Arrange + using SimpleTestPathContext pathContext = new SimpleTestPathContext(); ISettings settings = Settings.LoadDefaultSettings( - Directory.GetCurrentDirectory(), - configFileName: null, - machineWideSettings: new XPlatMachineWideSetting()); + pathContext.WorkingDirectory, + configFileName: null, + machineWideSettings: new XPlatMachineWideSetting()); PackageSourceProvider sourceProvider = new PackageSourceProvider(settings); string source = "invalid-source"; string expectedError = string.Format(CultureInfo.CurrentCulture, Strings.Error_InvalidSource, source); @@ -334,20 +355,22 @@ public async Task RunAsync_WhenSourceIsInvalid_ReturnsErrorExitCode() cancellationToken: System.Threading.CancellationToken.None); // Assert - Assert.Equal(ExitCodes.Error, exitCode); - Assert.Contains(expectedError, StoredErrorMessage); + exitCode.Should().Be(ExitCodes.Error); + StoredErrorMessage.Should().Contain(expectedError); } [Fact] public async Task RunAsync_WhenSourceHasNoSearchResource_LogsSearchServiceMissingError() { // Arrange + using SimpleTestPathContext pathContext = new SimpleTestPathContext(); + string source = $"{_fixture.ServerWithMultipleEndpoints.Uri}v3/indexWithNoSearchResource.json"; + pathContext.Settings.AddSource(source, source, allowInsecureConnectionsValue: "true"); ISettings settings = Settings.LoadDefaultSettings( - Directory.GetCurrentDirectory(), - configFileName: null, - machineWideSettings: new XPlatMachineWideSetting()); + pathContext.WorkingDirectory, + configFileName: pathContext.NuGetConfig, + machineWideSettings: new XPlatMachineWideSetting()); PackageSourceProvider sourceProvider = new PackageSourceProvider(settings); - string source = $"{_fixture.ServerWithMultipleEndpoints.Uri}v3/indexWithNoSearchResource.json"; string expectedError = Protocol.Strings.Protocol_MissingSearchService; PackageSearchArgs packageSearchArgs = new() { @@ -367,22 +390,24 @@ public async Task RunAsync_WhenSourceHasNoSearchResource_LogsSearchServiceMissin cancellationToken: System.Threading.CancellationToken.None); // Assert - Assert.Equal(ExitCodes.Success, exitCode); - Assert.Contains(expectedError, StoredErrorMessage); + exitCode.Should().Be(ExitCodes.Success); + StoredErrorMessage.Should().Contain(expectedError); } [Fact] public async Task RunAsync_HandlesOperationCanceledException_WhenCancellationIsRequested() { // Arrange + using SimpleTestPathContext pathContext = new SimpleTestPathContext(); + string source = $"{_fixture.ServerWithMultipleEndpoints.Uri}v3/indexWithNoSearchResource.json"; + pathContext.Settings.AddSource(source, source, allowInsecureConnectionsValue: "true"); ISettings settings = Settings.LoadDefaultSettings( - Directory.GetCurrentDirectory(), - configFileName: null, + pathContext.WorkingDirectory, + configFileName: pathContext.NuGetConfig, machineWideSettings: new XPlatMachineWideSetting()); PackageSourceProvider sourceProvider = new PackageSourceProvider(settings); var expectedError = "A task was canceled."; var cts = new CancellationTokenSource(); - string source = $"{_fixture.ServerWithMultipleEndpoints.Uri}v3/indexWithNoSearchResource.json"; PackageSearchArgs packageSearchArgs = new PackageSearchArgs { Skip = 0, @@ -404,17 +429,20 @@ public async Task RunAsync_HandlesOperationCanceledException_WhenCancellationIsR cancellationToken: cts.Token); // Assert - Assert.Equal(ExitCodes.Success, exitCode); - Assert.Contains(expectedError, StoredErrorMessage); + exitCode.Should().Be(ExitCodes.Success); + StoredErrorMessage.Should().Contain(expectedError); } [Fact] public async Task RunAsync_WhenPackageHasOnlyIdAndVersion_ReturnsValidNormalVerbosityOutput() { // Arrange + using SimpleTestPathContext pathContext = new SimpleTestPathContext(); + string source = $"{_fixture.ServerWithMultipleEndpoints.Uri}v3/index.json"; + pathContext.Settings.AddSource(source, source, allowInsecureConnectionsValue: "true"); ISettings settings = Settings.LoadDefaultSettings( - Directory.GetCurrentDirectory(), - configFileName: null, + pathContext.WorkingDirectory, + configFileName: pathContext.NuGetConfig, machineWideSettings: new XPlatMachineWideSetting()); PackageSourceProvider sourceProvider = new PackageSourceProvider(settings); @@ -439,16 +467,19 @@ await PackageSearchRunner.RunAsync( // Assert string message = _fixture.NormalizeNewlines(Message); - Assert.Contains(_fixture.ExpectedSearchResultNullInfoPackage, message); + message.Should().Contain(_fixture.ExpectedSearchResultNullInfoPackage); } [Fact] public async Task RunAsync_WhenPackageHasOnlyIdAndVersion_ReturnsValidMinimalVerbosityOutput() { // Arrange + using SimpleTestPathContext pathContext = new SimpleTestPathContext(); + string source = $"{_fixture.ServerWithMultipleEndpoints.Uri}v3/index.json"; + pathContext.Settings.AddSource(source, source, allowInsecureConnectionsValue: "true"); ISettings settings = Settings.LoadDefaultSettings( - Directory.GetCurrentDirectory(), - configFileName: null, + pathContext.WorkingDirectory, + configFileName: pathContext.NuGetConfig, machineWideSettings: new XPlatMachineWideSetting()); PackageSourceProvider sourceProvider = new PackageSourceProvider(settings); @@ -473,16 +504,19 @@ await PackageSearchRunner.RunAsync( // Assert string message = _fixture.NormalizeNewlines(Message); - Assert.Contains(_fixture.ExpectedSearchResultNullInfoPackage, message); + message.Should().Contain(_fixture.ExpectedSearchResultNullInfoPackage); } [Fact] public async Task RunAsync_WhenPackageHasOnlyIdAndVersion_ReturnsValidDetailedVerbosityOutput() { // Arrange + using SimpleTestPathContext pathContext = new SimpleTestPathContext(); + string source = $"{_fixture.ServerWithMultipleEndpoints.Uri}v3/index.json"; + pathContext.Settings.AddSource(source, source, allowInsecureConnectionsValue: "true"); ISettings settings = Settings.LoadDefaultSettings( - Directory.GetCurrentDirectory(), - configFileName: null, + pathContext.WorkingDirectory, + configFileName: pathContext.NuGetConfig, machineWideSettings: new XPlatMachineWideSetting()); PackageSourceProvider sourceProvider = new PackageSourceProvider(settings); @@ -507,7 +541,7 @@ await PackageSearchRunner.RunAsync( // Assert string message = _fixture.NormalizeNewlines(Message); - Assert.Contains(_fixture.ExpectedSearchResultNullInfoPackage, message); + message.Should().Contain(_fixture.ExpectedSearchResultNullInfoPackage); } } } diff --git a/src/nuget-client/test/NuGet.Core.Tests/NuGet.Commands.Test/Project2ProjectInLockFileTests.cs b/src/nuget-client/test/NuGet.Core.Tests/NuGet.Commands.Test/Project2ProjectInLockFileTests.cs index 52ca5986c47..369812e5a65 100644 --- a/src/nuget-client/test/NuGet.Core.Tests/NuGet.Commands.Test/Project2ProjectInLockFileTests.cs +++ b/src/nuget-client/test/NuGet.Core.Tests/NuGet.Commands.Test/Project2ProjectInLockFileTests.cs @@ -89,26 +89,6 @@ public async Task Project2ProjectInLockFile_VerifySnapshotVersions() var logger = new TestLogger(); var request = ProjectTestHelpers.CreateRestoreRequest(pathContext, logger, spec1, spec2, spec3); - //request.ExternalProjects.Add(new ExternalProjectReference( - // "project1", - // spec1, - // Path.Combine(project1.FullName, "project1.csproj"), - // new string[] { "project2" })); - - //request.ExternalProjects.Add(new ExternalProjectReference( - // "project2", - // spec2, - // Path.Combine(project2.FullName, "project2.xproj"), - // new string[] { "project3" })); - - //request.ExternalProjects.Add(new ExternalProjectReference( - // "project3", - // spec3, - // Path.Combine(project2.FullName, "project3.xproj"), - // new string[] { })); - - - //request.LockFilePath = Path.Combine(project1.FullName, "project.lock.json"); var format = new LockFileFormat(); // Act diff --git a/src/nuget-client/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/DependencyGraphSpecTests.cs b/src/nuget-client/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/DependencyGraphSpecTests.cs index 9bb6232cc4c..1df3aac1264 100644 --- a/src/nuget-client/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/DependencyGraphSpecTests.cs +++ b/src/nuget-client/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/DependencyGraphSpecTests.cs @@ -16,17 +16,14 @@ public void WithReplacedSpec() { // Arrange var packageSpecA = new PackageSpec(); - packageSpecA.Title = "A"; packageSpecA.RestoreMetadata = new ProjectRestoreMetadata() { ProjectUniqueName = "a", CentralPackageVersionsEnabled = false }; var dgSpec = new DependencyGraphSpec(); var packageSpecB = new PackageSpec(); - packageSpecB.Title = "B"; packageSpecB.RestoreMetadata = new ProjectRestoreMetadata() { ProjectUniqueName = "BBB" }; var packageSpecC = new PackageSpec(); - packageSpecC.Title = "C"; packageSpecC.RestoreMetadata = new ProjectRestoreMetadata() { ProjectUniqueName = "CCC" @@ -48,7 +45,6 @@ public void WithReplacedPackageSpecs_WithASinglePackageSpec_Succeeds() // Arrange var packageSpecA = new PackageSpec { - Title = "A", RestoreMetadata = new ProjectRestoreMetadata() { ProjectUniqueName = "a", @@ -57,7 +53,6 @@ public void WithReplacedPackageSpecs_WithASinglePackageSpec_Succeeds() }; var packageSpecB = new PackageSpec { - Title = "B", RestoreMetadata = new ProjectRestoreMetadata() { ProjectUniqueName = "BBB" @@ -65,7 +60,6 @@ public void WithReplacedPackageSpecs_WithASinglePackageSpec_Succeeds() }; var packageSpecC = new PackageSpec { - Title = "C", RestoreMetadata = new ProjectRestoreMetadata() { ProjectUniqueName = "CCC" @@ -98,7 +92,7 @@ public void WithReplacedPackageSpecs_WithASinglePackageSpec_Succeeds() dgSpecWithReplacedPackageA.Projects.Should().HaveCount(3); dgSpecWithReplacedPackageA.Restore.Should().HaveCount(1); - var packageSpecInAFromDgSpec = dgSpecWithReplacedPackageA.Projects.Single(e => e.Title.Equals("A")); + var packageSpecInAFromDgSpec = dgSpecWithReplacedPackageA.Projects.Single(e => e.RestoreMetadata.ProjectUniqueName.Equals("a")); packageSpecInAFromDgSpec.Should().Be(updatedPackageA); dgSpecWithReplacedPackageA.Restore.Single().Should().Be(updatedPackageA.RestoreMetadata.ProjectUniqueName); } diff --git a/src/nuget-client/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/NuGetPackageManagerTests/NuGetPackageManagerTelemetryTests.cs b/src/nuget-client/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/NuGetPackageManagerTests/NuGetPackageManagerTelemetryTests.cs index cac86e99185..c461b8674fb 100644 --- a/src/nuget-client/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/NuGetPackageManagerTests/NuGetPackageManagerTelemetryTests.cs +++ b/src/nuget-client/test/NuGet.Core.Tests/NuGet.PackageManagement.Test/NuGetPackageManagerTests/NuGetPackageManagerTelemetryTests.cs @@ -23,7 +23,7 @@ using NuGet.Test; using NuGet.Test.Utility; using NuGet.Versioning; -using NuGet.VisualStudio; +using NuGet.VisualStudio.Telemetry; using Test.Utility; using Xunit; using Xunit.Abstractions; diff --git a/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/ImportFrameworkTest.cs b/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/ImportFrameworkTest.cs index 850c637129d..7a3b8fbb004 100644 --- a/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/ImportFrameworkTest.cs +++ b/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/ImportFrameworkTest.cs @@ -12,7 +12,7 @@ namespace NuGet.ProjectModel.Test public class ImportFrameworkTest { [Fact] - public void ImportFramwork_UnknowFramework() + public void ImportFramework_UnknownFramework() { JObject configJson = JObject.Parse(@" { @@ -29,7 +29,7 @@ public void ImportFramwork_UnknowFramework() // Act & Assert var ex = Assert.Throws(() => JsonPackageSpecReader.GetPackageSpec(configJson.ToString(), "TestProject", "project.json")); - Assert.Equal("Imports contains an invalid framework: 'futureFramework' in 'project.json'.", ex.InnerException.Message); + Assert.Equal("Imports contains an invalid framework: 'futureFramework' in ''.", ex.InnerException.Message); } [Fact] diff --git a/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/IncludeExcludeFilesTests.cs b/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/IncludeExcludeFilesTests.cs deleted file mode 100644 index 4be0e1063c8..00000000000 --- a/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/IncludeExcludeFilesTests.cs +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using Newtonsoft.Json.Linq; -using Xunit; - -namespace NuGet.ProjectModel.Test -{ - public class IncludeExcludeFilesTests - { - private const long Seed = 0x1505L; - - [Fact] - public void Constructor_Always_InitializesProperties() - { - var files = new IncludeExcludeFiles(); - - Assert.Null(files.Exclude); - Assert.Null(files.ExcludeFiles); - Assert.Null(files.Include); - Assert.Null(files.IncludeFiles); - } - - [Fact] - public void HandleIncludeExcludeFiles_WhenJsonObjectIsNull_Throws() - { - var files = new IncludeExcludeFiles(); - - ArgumentNullException exception = Assert.Throws( - () => files.HandleIncludeExcludeFiles(jsonObject: null)); - - Assert.Equal("jsonObject", exception.ParamName); - } - - [Theory] - [InlineData("{}")] - [InlineData("{\"exclude\":null}")] - [InlineData("{\"excludeFiles\":null}")] - [InlineData("{\"include\":null}")] - [InlineData("{\"includeFiles\":null}")] - public void HandleIncludeExcludeFiles_WithNullForFiles_ReturnsFalse(string json) - { - JObject jsonObject = JObject.Parse(json); - var files = new IncludeExcludeFiles(); - - Assert.False(files.HandleIncludeExcludeFiles(jsonObject)); - Assert.Null(files.Exclude); - Assert.Null(files.ExcludeFiles); - Assert.Null(files.Include); - Assert.Null(files.IncludeFiles); - } - - [Theory] - [InlineData("{\"exclude\":[]}")] - [InlineData("{\"exclude\":[\"a\"]}", "a")] - public void HandleIncludeExcludeFiles_WithValidValueForExclude_ReturnsTrue( - string json, - params string[] expectedResults) - { - JObject jsonObject = JObject.Parse(json); - var files = new IncludeExcludeFiles(); - - Assert.True(files.HandleIncludeExcludeFiles(jsonObject)); - - Assert.Equal(expectedResults, files.Exclude); - Assert.Null(files.ExcludeFiles); - Assert.Null(files.Include); - Assert.Null(files.IncludeFiles); - } - - [Theory] - [InlineData("{\"excludeFiles\":[]}")] - [InlineData("{\"excludeFiles\":[\"a\"]}", "a")] - public void HandleIncludeExcludeFiles_WithValidValueForExcludeFiles_ReturnsTrue( - string json, - params string[] expectedResults) - { - JObject jsonObject = JObject.Parse(json); - var files = new IncludeExcludeFiles(); - - Assert.True(files.HandleIncludeExcludeFiles(jsonObject)); - - Assert.Null(files.Exclude); - Assert.Equal(expectedResults, files.ExcludeFiles); - Assert.Null(files.Include); - Assert.Null(files.IncludeFiles); - } - - [Theory] - [InlineData("{\"include\":[]}")] - [InlineData("{\"include\":[\"a\"]}", "a")] - public void HandleIncludeExcludeFiles_WithValidValueForInclude_ReturnsTrue( - string json, - params string[] expectedResults) - { - JObject jsonObject = JObject.Parse(json); - var files = new IncludeExcludeFiles(); - - Assert.True(files.HandleIncludeExcludeFiles(jsonObject)); - - Assert.Null(files.Exclude); - Assert.Null(files.ExcludeFiles); - Assert.Equal(expectedResults, files.Include); - Assert.Null(files.IncludeFiles); - } - - [Theory] - [InlineData("{\"includeFiles\":[]}")] - [InlineData("{\"includeFiles\":[\"a\"]}", "a")] - public void HandleIncludeExcludeFiles_WithValidValueForIncludeFiles_ReturnsTrue( - string json, - params string[] expectedResults) - { - JObject jsonObject = JObject.Parse(json); - var files = new IncludeExcludeFiles(); - - Assert.True(files.HandleIncludeExcludeFiles(jsonObject)); - - Assert.Null(files.Exclude); - Assert.Null(files.ExcludeFiles); - Assert.Null(files.Include); - Assert.Equal(expectedResults, files.IncludeFiles); - } - - [Fact] - public void GetHashCode_Always_HashesAllProperties() - { - IReadOnlyList exclude = new[] { "a" }; - IReadOnlyList excludeFiles = new[] { "b" }; - IReadOnlyList include = new[] { "c" }; - IReadOnlyList includeFiles = new[] { "d" }; - - int expectedResult = GetExpectedHashCode(exclude, excludeFiles, include, includeFiles); - - var files = new IncludeExcludeFiles(); - - files.Exclude = exclude; - files.ExcludeFiles = excludeFiles; - files.Include = include; - files.IncludeFiles = includeFiles; - - int actualResult = files.GetHashCode(); - - Assert.Equal(expectedResult, actualResult); - } - - [Fact] - public void Equals_WithOther_ReturnsCorrectValue() - { - var files1 = new IncludeExcludeFiles(); - var files2 = new IncludeExcludeFiles(); - - Assert.False(files1.Equals(other: null)); - Assert.True(files1.Equals(other: files1)); - Assert.True(files1.Equals(other: files2)); - - var files = new List() { "a" }; - - files1.Exclude = files; - Assert.False(files1.Equals(files2)); - files2.Exclude = files; - Assert.True(files1.Equals(files2)); - - files1.ExcludeFiles = files; - Assert.False(files1.Equals(files2)); - files2.ExcludeFiles = files; - Assert.True(files1.Equals(files2)); - - files1.Include = files; - Assert.False(files1.Equals(files2)); - files2.Include = files; - Assert.True(files1.Equals(files2)); - - files1.IncludeFiles = files; - Assert.False(files1.Equals(files2)); - files2.IncludeFiles = files; - Assert.True(files1.Equals(files2)); - } - - [Fact] - public void Equals_WithObj_ReturnsCorrectValue() - { - var files1 = new IncludeExcludeFiles(); - var files2 = new IncludeExcludeFiles(); - - Assert.False(files1.Equals(obj: null)); - Assert.False(files1.Equals(obj: "b")); - Assert.False(files1.Equals(obj: new object())); - Assert.True(files1.Equals(obj: files1)); - Assert.True(files1.Equals(obj: files2)); - } - - [Fact] - public void Clone_Always_CreatesDeepClone() - { - IReadOnlyList exclude = new[] { "a" }; - IReadOnlyList excludeFiles = new[] { "b" }; - IReadOnlyList include = new[] { "c" }; - IReadOnlyList includeFiles = new[] { "d" }; - - var expectedResult = new IncludeExcludeFiles() - { - Exclude = exclude, - ExcludeFiles = excludeFiles, - Include = include, - IncludeFiles = includeFiles - }; - int expectedHashCode = expectedResult.GetHashCode(); - - IncludeExcludeFiles actualResult = expectedResult.Clone(); - int actualHashCode = actualResult.GetHashCode(); - - Assert.NotSame(expectedResult, actualResult); - Assert.Equal(expectedResult, actualResult); - Assert.Equal(expectedHashCode, actualHashCode); - Assert.NotSame(expectedResult.Exclude, actualResult.Exclude); - Assert.Equal(exclude, actualResult.Exclude); - Assert.NotSame(expectedResult.ExcludeFiles, actualResult.ExcludeFiles); - Assert.Equal(excludeFiles, actualResult.ExcludeFiles); - Assert.NotSame(expectedResult.Include, actualResult.Include); - Assert.Equal(include, actualResult.Include); - Assert.NotSame(expectedResult.IncludeFiles, actualResult.IncludeFiles); - Assert.Equal(includeFiles, actualResult.IncludeFiles); - } - - private static int GetExpectedHashCode( - IReadOnlyList exclude, - IReadOnlyList excludeFiles, - IReadOnlyList include, - IReadOnlyList includeFiles) - { - long hashCode = Seed; - - hashCode = AddHashCodes(hashCode, include); - hashCode = AddHashCodes(hashCode, exclude); - hashCode = AddHashCodes(hashCode, includeFiles); - hashCode = AddHashCodes(hashCode, excludeFiles); - - return hashCode.GetHashCode(); - } - - private static long AddHashCode(long runningHashCode, int newHashCode) - { - return ((runningHashCode << 5) + runningHashCode) ^ newHashCode; - } - - private static long AddHashCodes(long hashCode, IEnumerable items) - { - long combinedHashCode = hashCode; - - if (items != null) - { - foreach (T item in items) - { - combinedHashCode = AddHashCode(combinedHashCode, item.GetHashCode()); - } - } - - return combinedHashCode; - } - } -} diff --git a/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/JsonPackageSpecReaderTests.cs b/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/JsonPackageSpecReaderTests.cs index aff4d19d36a..a13289530e9 100644 --- a/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/JsonPackageSpecReaderTests.cs +++ b/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/JsonPackageSpecReaderTests.cs @@ -13,7 +13,6 @@ using NuGet.Configuration; using NuGet.Frameworks; using NuGet.LibraryModel; -using NuGet.Packaging.Core; using NuGet.RuntimeModel; using NuGet.Versioning; using Test.Utility; @@ -195,293 +194,6 @@ public void PackageSpecReader_ExplicitIncludesOverrideTypePlatform(IEnvironmentV Assert.Equal(expected, dep.IncludeType); } - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), "{}", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""packOptions"": {} - }", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""packOptions"": { - ""foo"": [1, 2] - } - }", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""packOptions"": { - ""packageType"": null - } - }", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""packOptions"": { - ""packageType"": [] - } - }", MemberType = typeof(LockFileParsingEnvironmentVariable))] -#pragma warning disable CS0612 // Type or member is obsolete - public void PackageSpecReader_PackOptions_Default(IEnvironmentVariableReader environmentVariableReader, string json) - { - // Arrange & Act - var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); - - // Assert - Assert.NotNull(actual.PackOptions); - Assert.NotNull(actual.PackOptions.PackageType); - Assert.Empty(actual.PackOptions.PackageType); - } - - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), @" - ""packOptions"": { - ""packageType"": ""foo"" - } - }", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void PackageSpecReader_Malformed_Default(IEnvironmentVariableReader environmentVariableReader, string json) - { - // Arrange & Act - var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); - - // Assert - Assert.NotNull(actual.PackOptions); - Assert.NotNull(actual.PackOptions.PackageType); - Assert.Empty(actual.PackOptions.PackageType); - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""packOptions"": { - ""packageType"": ""foo"" - } - }", new[] { "foo" }, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""packOptions"": { - ""packageType"": ""foo, bar"" - } - }", new[] { "foo, bar" }, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""packOptions"": { - ""packageType"": [ ""foo"" ] - } - }", new[] { "foo" }, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""packOptions"": { - ""packageType"": [ ""foo, bar"" ] - } - }", new[] { "foo, bar" }, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""packOptions"": { - ""packageType"": [ ""foo"", ""bar"" ] - } - }", new[] { "foo", "bar" }, MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void PackageSpecReader_PackOptions_ValidPackageType(IEnvironmentVariableReader environmentVariableReader, string json, string[] expectedNames) - { - // Arrange - var expected = expectedNames - .Select(n => new PackageType(n, PackageType.EmptyVersion)) - .ToArray(); - - // Act - var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); - - // Assert - Assert.NotNull(actual.PackOptions); - Assert.NotNull(actual.PackOptions.PackageType); - Assert.Equal(expected, actual.PackOptions.PackageType.ToArray()); - } - - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""packOptions"": { - ""packageType"": 1 - } - }", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""packOptions"": { - ""packageType"": false - } - }", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""packOptions"": { - ""packageType"": 1.0 - } - }", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""packOptions"": { - ""packageType"": {} - } - }", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""packOptions"": { - ""packageType"": { - ""name"": ""foo"" - } - } - }", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""packOptions"": { - ""packageType"": [ - { ""name"": ""foo"" }, - { ""name"": ""bar"" } - ] - } - }", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""packOptions"": { - ""packageType"": [ - ""foo"", - null - ] - } - }", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""packOptions"": { - ""packageType"": [ - ""foo"", - true - ] - } - }", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void PackageSpecReader_PackOptions_InvalidPackageType(IEnvironmentVariableReader environmentVariableReader, string json) - { - // Arrange & Act & Assert - var actual = Assert.Throws( - () => GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader)); - - Assert.Contains("The pack options package type must be a string or array of strings in 'project.json'.", actual.Message); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void PackageSpecReader_PackOptions_Files1(IEnvironmentVariableReader environmentVariableReader) - { - // Arrange & Act - var json = @"{ - ""packOptions"": { - ""files"": { - ""include"": ""file1"", - ""exclude"": ""file2"", - ""includeFiles"": ""file3"", - ""excludeFiles"": ""file4"", - ""mappings"": { - ""dest/path"": ""./src/path"" - } - } - } - }"; - var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); - - // Assert - Assert.NotNull(actual.PackOptions); - Assert.Equal(1, actual.PackOptions.IncludeExcludeFiles.Include.Count); - Assert.Equal(1, actual.PackOptions.IncludeExcludeFiles.Exclude.Count); - Assert.Equal(1, actual.PackOptions.IncludeExcludeFiles.IncludeFiles.Count); - Assert.Equal(1, actual.PackOptions.IncludeExcludeFiles.ExcludeFiles.Count); - Assert.Equal("file1", actual.PackOptions.IncludeExcludeFiles.Include.First()); - Assert.Equal("file2", actual.PackOptions.IncludeExcludeFiles.Exclude.First()); - Assert.Equal("file3", actual.PackOptions.IncludeExcludeFiles.IncludeFiles.First()); - Assert.Equal("file4", actual.PackOptions.IncludeExcludeFiles.ExcludeFiles.First()); - Assert.NotNull(actual.PackOptions.Mappings); - Assert.Equal(1, actual.PackOptions.Mappings.Count()); - Assert.Equal("dest/path", actual.PackOptions.Mappings.First().Key); - Assert.Equal(1, actual.PackOptions.Mappings.First().Value.Include.Count()); - Assert.Null(actual.PackOptions.Mappings.First().Value.Exclude); - Assert.Null(actual.PackOptions.Mappings.First().Value.IncludeFiles); - Assert.Null(actual.PackOptions.Mappings.First().Value.ExcludeFiles); - Assert.Equal("./src/path", actual.PackOptions.Mappings.First().Value.Include.First()); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void PackageSpecReader_PackOptions_Files2(IEnvironmentVariableReader environmentVariableReader) - { - // Arrange & Act - var json = @"{ - ""packOptions"": { - ""files"": { - ""include"": [""file1a"", ""file1b""], - ""exclude"": [""file2a"", ""file2b""], - ""includeFiles"": [""file3a"", ""file3b""], - ""excludeFiles"": [""file4a"", ""file4b""], - ""mappings"": { - ""dest/path1"": [""./src/path1"", ""./src/path2""], - ""dest/path2"": { - ""includeFiles"": [""map1a"", ""map1b""], - }, - } - } - } - }"; - var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); - - // Assert - Assert.NotNull(actual.PackOptions); - Assert.Equal(2, actual.PackOptions.IncludeExcludeFiles.Include.Count); - Assert.Equal(2, actual.PackOptions.IncludeExcludeFiles.Exclude.Count); - Assert.Equal(2, actual.PackOptions.IncludeExcludeFiles.IncludeFiles.Count); - Assert.Equal(2, actual.PackOptions.IncludeExcludeFiles.ExcludeFiles.Count); - Assert.Equal("file1a", actual.PackOptions.IncludeExcludeFiles.Include.First()); - Assert.Equal("file2a", actual.PackOptions.IncludeExcludeFiles.Exclude.First()); - Assert.Equal("file3a", actual.PackOptions.IncludeExcludeFiles.IncludeFiles.First()); - Assert.Equal("file4a", actual.PackOptions.IncludeExcludeFiles.ExcludeFiles.First()); - Assert.Equal("file1b", actual.PackOptions.IncludeExcludeFiles.Include.Last()); - Assert.Equal("file2b", actual.PackOptions.IncludeExcludeFiles.Exclude.Last()); - Assert.Equal("file3b", actual.PackOptions.IncludeExcludeFiles.IncludeFiles.Last()); - Assert.Equal("file4b", actual.PackOptions.IncludeExcludeFiles.ExcludeFiles.Last()); - Assert.NotNull(actual.PackOptions.Mappings); - Assert.Equal(2, actual.PackOptions.Mappings.Count()); - Assert.Equal("dest/path1", actual.PackOptions.Mappings.First().Key); - Assert.Equal("dest/path2", actual.PackOptions.Mappings.Last().Key); - Assert.Equal(2, actual.PackOptions.Mappings.First().Value.Include.Count()); - Assert.Null(actual.PackOptions.Mappings.First().Value.Exclude); - Assert.Null(actual.PackOptions.Mappings.First().Value.IncludeFiles); - Assert.Null(actual.PackOptions.Mappings.First().Value.ExcludeFiles); - Assert.Equal("./src/path1", actual.PackOptions.Mappings.First().Value.Include.First()); - Assert.Equal("./src/path2", actual.PackOptions.Mappings.First().Value.Include.Last()); - Assert.Null(actual.PackOptions.Mappings.Last().Value.Include); - Assert.Null(actual.PackOptions.Mappings.Last().Value.Exclude); - Assert.Null(actual.PackOptions.Mappings.Last().Value.ExcludeFiles); - Assert.Equal("map1a", actual.PackOptions.Mappings.Last().Value.IncludeFiles.First()); - Assert.Equal("map1b", actual.PackOptions.Mappings.Last().Value.IncludeFiles.Last()); - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), "{}", null, true, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""buildOptions"": {} - }", null, false, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""buildOptions"": { - ""outputName"": ""dllName"" - } - }", "dllName", false, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""buildOptions"": { - ""outputName"": ""dllName2"", - ""emitEntryPoint"": true - } - }", "dllName2", false, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), @"{ - ""buildOptions"": { - ""outputName"": null - } - }", null, false, MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void PackageSpecReader_BuildOptions(IEnvironmentVariableReader environmentVariableReader, string json, string expectedValue, bool nullBuildOptions) - { - // Arrange & Act - var actual = GetPackageSpec(json, "TestProject", "project.json", null, environmentVariableReader); - - // Assert - if (nullBuildOptions) - { - Assert.Null(actual.BuildOptions); - } - else - { - Assert.NotNull(actual.BuildOptions); - Assert.Equal(expectedValue, actual.BuildOptions.OutputName); - } - } -#pragma warning restore CS0612 // Type or member is obsolete - [Theory] [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] public void PackageSpecReader_ReadsWithoutRestoreSettings(IEnvironmentVariableReader environmentVariableReader) @@ -994,219 +706,6 @@ public void PackageSpecReader_RuntimeIdentifierPathNullIfEmpty(IEnvironmentVaria Assert.Null(spec.TargetFrameworks.First().RuntimeIdentifierGraphPath); } -#pragma warning disable CS0612 // Type or member is obsolete - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenAuthorsPropertyIsAbsent_ReturnsEmptyAuthors(IEnvironmentVariableReader environmentVariableReader) - { - PackageSpec packageSpec = GetPackageSpec("{}", environmentVariableReader); - - Assert.Empty(packageSpec.Authors); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenAuthorsValueIsNull_ReturnsEmptyAuthors(IEnvironmentVariableReader environmentVariableReader) - { - PackageSpec packageSpec = GetPackageSpec("{\"authors\":null}", environmentVariableReader); - - Assert.Empty(packageSpec.Authors); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenAuthorsValueIsString_ReturnsEmptyAuthors(IEnvironmentVariableReader environmentVariableReader) - { - PackageSpec packageSpec = GetPackageSpec("{\"authors\":\"b\"}", environmentVariableReader); - - Assert.Empty(packageSpec.Authors); - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), "", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "/**/", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenAuthorsValueIsEmptyArray_ReturnsEmptyAuthors(IEnvironmentVariableReader environmentVariableReader, string value) - { - PackageSpec packageSpec = GetPackageSpec($"{{\"authors\":[{value}]}}", environmentVariableReader); - - Assert.Empty(packageSpec.Authors); - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), "{}", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[]", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenAuthorsValueElementIsNotConvertibleToString_Throws(IEnvironmentVariableReader environmentVariableReader, string value) - { - var json = $"{{\"authors\":[{value}]}}"; - - Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "true", "True", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "-2", "-2", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "3.14", "3.14", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenAuthorsValueElementIsConvertibleToString_ReturnsAuthor(IEnvironmentVariableReader environmentVariableReader, string value, string expectedValue) - { - PackageSpec packageSpec = GetPackageSpec($"{{\"authors\":[{value}]}}", environmentVariableReader); - - Assert.Collection(packageSpec.Authors, author => Assert.Equal(expectedValue, author)); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenBuildOptionsPropertyIsAbsent_ReturnsNullBuildOptions(IEnvironmentVariableReader environmentVariableReader) - { - PackageSpec packageSpec = GetPackageSpec("{}", environmentVariableReader); - - Assert.Null(packageSpec.BuildOptions); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenBuildOptionsValueIsEmptyObject_ReturnsBuildOptions(IEnvironmentVariableReader environmentVariableReader) - { - PackageSpec packageSpec = GetPackageSpec("{\"buildOptions\":{}}", environmentVariableReader); - - Assert.NotNull(packageSpec.BuildOptions); - Assert.Null(packageSpec.BuildOptions.OutputName); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenBuildOptionsValueOutputNameIsNull_ReturnsNullOutputName(IEnvironmentVariableReader environmentVariableReader) - { - PackageSpec packageSpec = GetPackageSpec("{\"buildOptions\":{\"outputName\":null}}", environmentVariableReader); - - Assert.Null(packageSpec.BuildOptions.OutputName); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenBuildOptionsValueOutputNameIsValid_ReturnsOutputName(IEnvironmentVariableReader environmentVariableReader) - { - const string expectedResult = "a"; - - var json = $"{{\"buildOptions\":{{\"outputName\":\"{expectedResult}\"}}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Equal(expectedResult, packageSpec.BuildOptions.OutputName); - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), "-2", "-2", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "3.14", "3.14", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "true", "True", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenBuildOptionsValueOutputNameIsConvertibleToString_ReturnsOutputName(IEnvironmentVariableReader environmentVariableReader, string outputName, string expectedValue) - { - PackageSpec packageSpec = GetPackageSpec($"{{\"buildOptions\":{{\"outputName\":{outputName}}}}}", environmentVariableReader); - - Assert.Equal(expectedValue, packageSpec.BuildOptions.OutputName); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenContentFilesPropertyIsAbsent_ReturnsEmptyContentFiles(IEnvironmentVariableReader environmentVariableReader) - { - PackageSpec packageSpec = GetPackageSpec("{}", environmentVariableReader); - - Assert.Empty(packageSpec.ContentFiles); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenContentFilesValueIsNull_ReturnsEmptyContentFiles(IEnvironmentVariableReader environmentVariableReader) - { - PackageSpec packageSpec = GetPackageSpec("{\"contentFiles\":null}", environmentVariableReader); - - Assert.Empty(packageSpec.ContentFiles); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenContentFilesValueIsString_ReturnsEmptyContentFiles(IEnvironmentVariableReader environmentVariableReader) - { - PackageSpec packageSpec = GetPackageSpec("{\"contentFiles\":\"a\"}", environmentVariableReader); - - Assert.Empty(packageSpec.ContentFiles); - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), "", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "/**/", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenContentFilesValueIsEmptyArray_ReturnsEmptyContentFiles(IEnvironmentVariableReader environmentVariableReader, string value) - { - PackageSpec packageSpec = GetPackageSpec($"{{\"contentFiles\":[{value}]}}", environmentVariableReader); - - Assert.Empty(packageSpec.ContentFiles); - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), "{}", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[]", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenContentFilesValueElementIsNotConvertibleToString_Throws(IEnvironmentVariableReader environmentVariableReader, string value) - { - var json = $"{{\"contentFiles\":[{value}]}}"; - - Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "true", "True", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "-2", "-2", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "3.14", "3.14", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenContentFilesValueElementIsConvertibleToString_ReturnsContentFile(IEnvironmentVariableReader environmentVariableReader, string value, string expectedValue) - { - PackageSpec packageSpec = GetPackageSpec($"{{\"contentFiles\":[{value}]}}", environmentVariableReader); - - Assert.Collection(packageSpec.ContentFiles, contentFile => Assert.Equal(expectedValue, contentFile)); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenCopyrightPropertyIsAbsent_ReturnsNullCopyright(IEnvironmentVariableReader environmentVariableReader) - { - PackageSpec packageSpec = GetPackageSpec("{}", environmentVariableReader); - - Assert.Null(packageSpec.Copyright); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenCopyrightValueIsNull_ReturnsNullCopyright(IEnvironmentVariableReader environmentVariableReader) - { - PackageSpec packageSpec = GetPackageSpec("{\"copyright\":null}", environmentVariableReader); - - Assert.Null(packageSpec.Copyright); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenCopyrightValueIsString_ReturnsCopyright(IEnvironmentVariableReader environmentVariableReader) - { - const string expectedResult = "a"; - - PackageSpec packageSpec = GetPackageSpec($"{{\"copyright\":\"{expectedResult}\"}}", environmentVariableReader); - - Assert.Equal(expectedResult, packageSpec.Copyright); - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "true", "True", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "-2", "-2", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "3.14", "3.14", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenCopyrightValueIsConvertibleToString_ReturnsCopyright(IEnvironmentVariableReader environmentVariableReader, string value, string expectedValue) - { - PackageSpec packageSpec = GetPackageSpec($"{{\"copyright\":{value}}}", environmentVariableReader); - - Assert.Equal(expectedValue, packageSpec.Copyright); - } -#pragma warning restore CS0612 // Type or member is obsolete - [Theory] [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] public void GetPackageSpec_WhenDependenciesPropertyIsAbsent_ReturnsEmptyDependencies(IEnvironmentVariableReader environmentVariableReader) @@ -1563,50 +1062,6 @@ public void GetPackageSpec_WhenDependenciesDependencyVersionCentrallyManagedValu Assert.Equal(expectedValue, dependency.VersionCentrallyManaged); } -#pragma warning disable CS0612 // Type or member is obsolete - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenDescriptionPropertyIsAbsent_ReturnsNullDescription(IEnvironmentVariableReader environmentVariableReader) - { - PackageSpec packageSpec = GetPackageSpec("{}", environmentVariableReader); - - Assert.Null(packageSpec.Description); - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), null, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "b", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenDescriptionValueIsValid_ReturnsDescription(IEnvironmentVariableReader environmentVariableReader, string expectedResult) - { - string description = expectedResult == null ? "null" : $"\"{expectedResult}\""; - PackageSpec packageSpec = GetPackageSpec($"{{\"description\":{description}}}", environmentVariableReader); - - Assert.Equal(expectedResult, packageSpec.Description); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenLanguagePropertyIsAbsent_ReturnsNullLanguage(IEnvironmentVariableReader environmentVariableReader) - { - PackageSpec packageSpec = GetPackageSpec("{}", environmentVariableReader); - - Assert.Null(packageSpec.Language); - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), null, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "b", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenLanguageValueIsValid_ReturnsLanguage(IEnvironmentVariableReader environmentVariableReader, string expectedResult) - { - string language = expectedResult == null ? "null" : $"\"{expectedResult}\""; - PackageSpec packageSpec = GetPackageSpec($"{{\"language\":{language}}}", environmentVariableReader); - - Assert.Equal(expectedResult, packageSpec.Language); - } -#pragma warning restore CS0612 // Type or member is obsolete - [Theory] [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] public void GetPackageSpec_WhenFrameworksPropertyIsAbsent_ReturnsEmptyFrameworks(IEnvironmentVariableReader environmentVariableReader) @@ -2575,7 +2030,7 @@ public void GetPackageSpec_WhenFrameworksImportsValueContainsInvalidValue_Throws if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) { Assert.Equal( - $"Error reading '' at line 1 column 20 : Imports contains an invalid framework: '{expectedImport}' in 'project.json'.", + $"Error reading '' at line 1 column 20 : Imports contains an invalid framework: '{expectedImport}' in ''.", exception.Message); Assert.Equal(1, exception.Line); Assert.Equal(20, exception.Column); @@ -2583,7 +2038,7 @@ public void GetPackageSpec_WhenFrameworksImportsValueContainsInvalidValue_Throws else { Assert.Equal( - $"Error reading '' : Imports contains an invalid framework: '{expectedImport}' in 'project.json'.", + $"Error reading '' : Imports contains an invalid framework: '{expectedImport}' in ''.", exception.Message); } } @@ -2665,457 +2120,21 @@ public void GetPackageSpec_WhenFrameworksWarnValueIsValid_ReturnsWarn(IEnvironme Assert.Equal(expectedResult, framework.Warn); } -#pragma warning disable CS0612 // Type or member is obsolete [Theory] [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackIncludePropertyIsAbsent_ReturnsEmptyPackInclude(IEnvironmentVariableReader environmentVariableReader) + public void GetPackageSpec_WhenRestorePropertyIsAbsent_ReturnsNullRestoreMetadata(IEnvironmentVariableReader environmentVariableReader) { - PackageSpec packageSpec = GetPackageSpec("{}", environmentVariableReader); + const string json = "{}"; + PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - Assert.Empty(packageSpec.PackInclude); + Assert.Null(packageSpec.RestoreMetadata); } [Theory] [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackIncludePropertyIsValid_ReturnsPackInclude(IEnvironmentVariableReader environmentVariableReader) + public void GetPackageSpec_WhenRestoreValueIsEmptyObject_ReturnsRestoreMetadata(IEnvironmentVariableReader environmentVariableReader) { - var expectedResults = new List>() { new KeyValuePair("a", "b"), new KeyValuePair("c", "d") }; - var json = $"{{\"packInclude\":{{\"{expectedResults[0].Key}\":\"{expectedResults[0].Value}\",\"{expectedResults[1].Key}\":\"{expectedResults[1].Value}\"}}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Collection( - packageSpec.PackInclude, - actualResult => Assert.Equal(expectedResults[0], actualResult), - actualResult => Assert.Equal(expectedResults[1], actualResult)); - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), "{}", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "{\"packOptions\":null}", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsPropertyIsAbsentOrValueIsNull_ReturnsPackOptions(IEnvironmentVariableReader environmentVariableReader, string json) - { - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.NotNull(packageSpec.PackOptions); - Assert.Null(packageSpec.PackOptions.IncludeExcludeFiles); - Assert.Empty(packageSpec.PackOptions.Mappings); - Assert.Empty(packageSpec.PackOptions.PackageType); - - Assert.Null(packageSpec.IconUrl); - Assert.Null(packageSpec.LicenseUrl); - Assert.Empty(packageSpec.Owners); - Assert.Null(packageSpec.ProjectUrl); - Assert.Null(packageSpec.ReleaseNotes); - Assert.False(packageSpec.RequireLicenseAcceptance); - Assert.Null(packageSpec.Summary); - Assert.Empty(packageSpec.Tags); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsPropertyIsAbsent_OwnersAndTagsAreEmpty(IEnvironmentVariableReader environmentVariableReader) - { - const string json = "{\"owners\":[\"a\"],\"tags\":[\"b\"]}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Empty(packageSpec.Owners); - Assert.Empty(packageSpec.Tags); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsPropertyIsEmptyObject_ReturnsPackOptions(IEnvironmentVariableReader environmentVariableReader) - { - string json = "{\"packOptions\":{}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.NotNull(packageSpec.PackOptions); - Assert.Null(packageSpec.PackOptions.IncludeExcludeFiles); - Assert.Null(packageSpec.PackOptions.Mappings); - Assert.Empty(packageSpec.PackOptions.PackageType); - - Assert.Null(packageSpec.IconUrl); - Assert.Null(packageSpec.LicenseUrl); - Assert.Empty(packageSpec.Owners); - Assert.Null(packageSpec.ProjectUrl); - Assert.Null(packageSpec.ReleaseNotes); - Assert.False(packageSpec.RequireLicenseAcceptance); - Assert.Null(packageSpec.Summary); - Assert.Empty(packageSpec.Tags); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsValueIsValid_ReturnsPackOptions(IEnvironmentVariableReader environmentVariableReader) - { - const string iconUrl = "a"; - const string licenseUrl = "b"; - string[] owners = { "c", "d" }; - const string projectUrl = "e"; - const string releaseNotes = "f"; - const bool requireLicenseAcceptance = true; - const string summary = "g"; - string[] tags = { "h", "i" }; - - var json = $"{{\"packOptions\":{{\"iconUrl\":\"{iconUrl}\",\"licenseUrl\":\"{licenseUrl}\",\"owners\":[{string.Join(",", owners.Select(owner => $"\"{owner}\""))}]," + - $"\"projectUrl\":\"{projectUrl}\",\"releaseNotes\":\"{releaseNotes}\",\"requireLicenseAcceptance\":{requireLicenseAcceptance.ToString().ToLowerInvariant()}," + - $"\"summary\":\"{summary}\",\"tags\":[{string.Join(",", tags.Select(tag => $"\"{tag}\""))}]}}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.NotNull(packageSpec.PackOptions); - Assert.Null(packageSpec.PackOptions.IncludeExcludeFiles); - Assert.Null(packageSpec.PackOptions.Mappings); - Assert.Empty(packageSpec.PackOptions.PackageType); - Assert.Equal(iconUrl, packageSpec.IconUrl); - Assert.Equal(licenseUrl, packageSpec.LicenseUrl); - Assert.Equal(owners, packageSpec.Owners); - Assert.Equal(projectUrl, packageSpec.ProjectUrl); - Assert.Equal(releaseNotes, packageSpec.ReleaseNotes); - Assert.Equal(requireLicenseAcceptance, packageSpec.RequireLicenseAcceptance); - Assert.Equal(summary, packageSpec.Summary); - Assert.Equal(tags, packageSpec.Tags); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsPackageTypeValueIsNull_ReturnsEmptyPackageTypes(IEnvironmentVariableReader environmentVariableReader) - { - const string json = "{\"packOptions\":{\"packageType\":null}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Empty(packageSpec.PackOptions.PackageType); - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), "true", 34, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "-2", 32, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "3.14", 34, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "{}", 31, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[true]", 31, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[-2]", 31, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[3.14]", 31, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[null]", 31, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[{}]", 31, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[[]]", 31, MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsPackageTypeIsInvalid_Throws(IEnvironmentVariableReader environmentVariableReader, string value, int expectedColumn) - { - var json = $"{{\"packOptions\":{{\"packageType\":{value}}}}}"; - - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); - - Assert.Null(exception.InnerException); - Assert.Equal("The pack options package type must be a string or array of strings in 'project.json'.", exception.Message); - - if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) - { - Assert.Equal(1, exception.Line); - Assert.Equal(expectedColumn, exception.Column); - } - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "\"a,b\"", "a,b", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[\"a\"]", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[\"a b\"]", "a b", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsPackageTypeValueIsValid_ReturnsPackageTypes(IEnvironmentVariableReader environmentVariableReader, string value, string expectedName) - { - var expectedResult = new PackageType(expectedName, PackageType.EmptyVersion); - var json = $"{{\"packOptions\":{{\"packageType\":{value}}}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Collection( - packageSpec.PackOptions.PackageType, - actualResult => Assert.Equal(expectedResult, actualResult)); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsFilesValueIsNull_ReturnsNullInclude(IEnvironmentVariableReader environmentVariableReader) - { - const string json = "{\"packOptions\":{\"files\":null}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Null(packageSpec.PackOptions.IncludeExcludeFiles); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsFilesValueIsEmptyObject_ReturnsNullInclude(IEnvironmentVariableReader environmentVariableReader) - { - const string json = "{\"packOptions\":{\"files\":{}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Null(packageSpec.PackOptions.IncludeExcludeFiles); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsFilesIncludeValueIsNull_ReturnsNullIncludeExcludeFiles(IEnvironmentVariableReader environmentVariableReader) - { - const string json = "{\"packOptions\":{\"files\":{\"include\":null}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Null(packageSpec.PackOptions.IncludeExcludeFiles); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsFilesIncludeValueIsEmptyArray_ReturnsEmptyInclude(IEnvironmentVariableReader environmentVariableReader) - { - const string json = "{\"packOptions\":{\"files\":{\"include\":[]}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Empty(packageSpec.PackOptions.IncludeExcludeFiles.Include); - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "\"a, b\"", "a, b", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[null]", null, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[\"\"]", "", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[\"a\"]", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[\"a, b\"]", "a, b", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[\"a\", \"b\"]", "a", "b", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsFilesIncludeValueIsValid_ReturnsInclude(IEnvironmentVariableReader environmentVariableReader, string value, params string[] expectedResults) - { - expectedResults = expectedResults ?? new string[] { null }; - - var json = $"{{\"packOptions\":{{\"files\":{{\"include\":{value}}}}}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Equal(expectedResults, packageSpec.PackOptions.IncludeExcludeFiles.Include); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsFilesIncludeFilesValueIsNull_ReturnsNullIncludeExcludeFiles(IEnvironmentVariableReader environmentVariableReader) - { - const string json = "{\"packOptions\":{\"files\":{\"includeFiles\":null}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Null(packageSpec.PackOptions.IncludeExcludeFiles); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsFilesIncludeFilesValueIsEmptyArray_ReturnsEmptyIncludeFiles(IEnvironmentVariableReader environmentVariableReader) - { - const string json = "{\"packOptions\":{\"files\":{\"includeFiles\":[]}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Empty(packageSpec.PackOptions.IncludeExcludeFiles.IncludeFiles); - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "\"a, b\"", "a, b", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[null]", null, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[\"\"]", "", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[\"a\"]", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[\"a, b\"]", "a, b", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[\"a\", \"b\"]", "a", "b", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsFilesIncludeFilesValueIsValid_ReturnsIncludeFiles(IEnvironmentVariableReader environmentVariableReader, string value, params string[] expectedResults) - { - expectedResults = expectedResults ?? new string[] { null }; - - var json = $"{{\"packOptions\":{{\"files\":{{\"includeFiles\":{value}}}}}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Equal(expectedResults, packageSpec.PackOptions.IncludeExcludeFiles.IncludeFiles); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsFilesExcludeValueIsNull_ReturnsNullIncludeExcludeFiles(IEnvironmentVariableReader environmentVariableReader) - { - const string json = "{\"packOptions\":{\"files\":{\"exclude\":null}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Null(packageSpec.PackOptions.IncludeExcludeFiles); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsFilesExcludeValueIsEmptyArray_ReturnsEmptyExclude(IEnvironmentVariableReader environmentVariableReader) - { - const string json = "{\"packOptions\":{\"files\":{\"exclude\":[]}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Empty(packageSpec.PackOptions.IncludeExcludeFiles.Exclude); - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "\"a, b\"", "a, b", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[null]", null, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[\"\"]", "", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[\"a\"]", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[\"a, b\"]", "a, b", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[\"a\", \"b\"]", "a", "b", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsFilesExcludeValueIsValid_ReturnsExclude(IEnvironmentVariableReader environmentVariableReader, string value, params string[] expectedResults) - { - expectedResults = expectedResults ?? new string[] { null }; - - var json = $"{{\"packOptions\":{{\"files\":{{\"exclude\":{value}}}}}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Equal(expectedResults, packageSpec.PackOptions.IncludeExcludeFiles.Exclude); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsFilesExcludeFilesValueIsNull_ReturnsNullIncludeExcludeFiles(IEnvironmentVariableReader environmentVariableReader) - { - const string json = "{\"packOptions\":{\"files\":{\"excludeFiles\":null}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Null(packageSpec.PackOptions.IncludeExcludeFiles); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsFilesExcludeFilesValueIsEmptyArray_ReturnsEmptyExcludeFiles(IEnvironmentVariableReader environmentVariableReader) - { - const string json = "{\"packOptions\":{\"files\":{\"excludeFiles\":[]}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Empty(packageSpec.PackOptions.IncludeExcludeFiles.ExcludeFiles); - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "\"a, b\"", "a, b", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[null]", null, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[\"\"]", "", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[\"a\"]", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[\"a, b\"]", "a, b", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[\"a\", \"b\"]", "a", "b", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsFilesExcludeFilesValueIsValid_ReturnsExcludeFiles(IEnvironmentVariableReader environmentVariableReader, string value, params string[] expectedResults) - { - expectedResults = expectedResults ?? new string[] { null }; - - var json = $"{{\"packOptions\":{{\"files\":{{\"excludeFiles\":{value}}}}}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Equal(expectedResults, packageSpec.PackOptions.IncludeExcludeFiles.ExcludeFiles); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsFilesMappingsPropertyIsAbsent_ReturnsNullMappings(IEnvironmentVariableReader environmentVariableReader) - { - const string json = "{\"packOptions\":{\"files\":{}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Null(packageSpec.PackOptions.Mappings); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsFilesMappingsValueIsNull_ReturnsNullMappings(IEnvironmentVariableReader environmentVariableReader) - { - const string json = "{\"packOptions\":{\"files\":{\"mappings\":null}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Null(packageSpec.PackOptions.Mappings); - } - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), "\"b\"", "b", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "\"b,c\"", "b,c", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "[\"b\", \"c\"]", "b", "c", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsFilesMappingsValueIsValid_ReturnsMappings(IEnvironmentVariableReader environmentVariableReader, string value, params string[] expectedIncludes) - { - var expectedResults = new Dictionary() - { - { "a", new IncludeExcludeFiles() { Include = expectedIncludes } } - }; - var json = $"{{\"packOptions\":{{\"files\":{{\"mappings\":{{\"a\":{value}}}}}}}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Equal(expectedResults, packageSpec.PackOptions.Mappings); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsFilesMappingsValueHasMultipleMappings_ReturnsMappings(IEnvironmentVariableReader environmentVariableReader) - { - var expectedResults = new Dictionary() - { - { "a", new IncludeExcludeFiles() { Include = new[] { "b" } } }, - { "c", new IncludeExcludeFiles() { Include = new[] { "d", "e" } } } - }; - const string json = "{\"packOptions\":{\"files\":{\"mappings\":{\"a\":\"b\",\"c\":[\"d\", \"e\"]}}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Equal(expectedResults, packageSpec.PackOptions.Mappings); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenPackOptionsFilesMappingsValueHasFiles_ReturnsMappings(IEnvironmentVariableReader environmentVariableReader) - { - var expectedResults = new Dictionary() - { - { - "a", - new IncludeExcludeFiles() - { - Include = new [] { "b" }, - IncludeFiles = new [] { "c" }, - Exclude = new [] { "d" }, - ExcludeFiles = new [] { "e" } - } - } - }; - const string json = "{\"packOptions\":{\"files\":{\"mappings\":{\"a\":{\"include\":\"b\",\"includeFiles\":\"c\",\"exclude\":\"d\",\"excludeFiles\":\"e\"}}}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Equal(expectedResults, packageSpec.PackOptions.Mappings); - } -#pragma warning restore CS0612 // Type or member is obsolete - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenRestorePropertyIsAbsent_ReturnsNullRestoreMetadata(IEnvironmentVariableReader environmentVariableReader) - { - const string json = "{}"; - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Null(packageSpec.RestoreMetadata); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenRestoreValueIsEmptyObject_ReturnsRestoreMetadata(IEnvironmentVariableReader environmentVariableReader) - { - const string json = "{\"restore\":{}}"; + const string json = "{\"restore\":{}}"; PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); Assert.NotNull(packageSpec.RestoreMetadata); @@ -3692,81 +2711,6 @@ public void GetPackageSpec_WhenSupportsValueIsValidWithCompatibilityProfilesAndF Assert.Equal(expectedResult, packageSpec.RuntimeGraph); } -#pragma warning disable CS0612 // Type or member is obsolete - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenScriptsValueIsEmptyObject_ReturnsScripts(IEnvironmentVariableReader environmentVariableReader) - { - const string json = "{\"scripts\":{}}"; - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Empty(packageSpec.Scripts); - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenScriptsValueIsInvalid_Throws(IEnvironmentVariableReader environmentVariableReader) - { - var json = "{\"scripts\":{\"a\":0}}"; - - FileFormatException exception = Assert.Throws(() => GetPackageSpec(json, environmentVariableReader)); - - Assert.Equal("The value of a script in 'project.json' can only be a string or an array of strings", exception.Message); - Assert.Null(exception.InnerException); - - if (string.Equals(bool.TrueString, environmentVariableReader.GetEnvironmentVariable(JsonUtility.NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING))) - { - Assert.Equal(1, exception.Line); - Assert.Equal(17, exception.Column); - } - } - - [Theory] - [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenScriptsValueIsValid_ReturnsScripts(IEnvironmentVariableReader environmentVariableReader) - { - const string name0 = "a"; - const string name1 = "b"; - const string script0 = "c"; - const string script1 = "d"; - const string script2 = "e"; - - var json = $"{{\"scripts\":{{\"{name0}\":\"{script0}\",\"{name1}\":[\"{script1}\",\"{script2}\"]}}}}"; - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Collection( - packageSpec.Scripts, - actualResult => - { - Assert.Equal(name0, actualResult.Key); - Assert.Collection( - actualResult.Value, - actualScript => Assert.Equal(script0, actualScript)); - }, - actualResult => - { - Assert.Equal(name1, actualResult.Key); - Assert.Collection( - actualResult.Value, - actualScript => Assert.Equal(script1, actualScript), - actualScript => Assert.Equal(script2, actualScript)); - }); - } -#pragma warning restore CS0612 // Type or member is obsolete - - [Theory] - [MemberData(nameof(TestEnvironmentVariableReader), "null", null, MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "\"\"", "", MemberType = typeof(LockFileParsingEnvironmentVariable))] - [MemberData(nameof(TestEnvironmentVariableReader), "\"a\"", "a", MemberType = typeof(LockFileParsingEnvironmentVariable))] - public void GetPackageSpec_WhenTitleValueIsValid_ReturnsTitle(IEnvironmentVariableReader environmentVariableReader, string value, string expectedResult) - { - var json = $"{{\"title\":{value}}}"; - - PackageSpec packageSpec = GetPackageSpec(json, environmentVariableReader); - - Assert.Equal(expectedResult, packageSpec.Title); - } - [Theory] [MemberData(nameof(LockFileParsingEnvironmentVariable.TestEnvironmentVariableReader), MemberType = typeof(LockFileParsingEnvironmentVariable))] public void GetPackageSpec_WhenNameIsNull_RestoreMetadataProvidesFallbackName(IEnvironmentVariableReader environmentVariableReader) diff --git a/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileEqualityTests.cs b/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileEqualityTests.cs index 36461d2c4e7..98d6d59d9fa 100644 --- a/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileEqualityTests.cs +++ b/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileEqualityTests.cs @@ -323,16 +323,10 @@ public void Equals_WithEquivalentPackageSpec_ReturnsTrue() var leftSide = new LockFile { PackageSpec = new PackageSpec() - { - Title = "a" - } }; var rightSide = new LockFile { PackageSpec = new PackageSpec() - { - Title = "a" - } }; leftSide.Should().Be(rightSide); @@ -345,14 +339,14 @@ public void Equals_WithDifferentPackageSpec_ReturnsFalse() { PackageSpec = new PackageSpec() { - Title = "a" + Version = Versioning.NuGetVersion.Parse("1.0.0"), } }; var rightSide = new LockFile { PackageSpec = new PackageSpec() { - Title = "b" + Version = Versioning.NuGetVersion.Parse("2.0.0"), } }; diff --git a/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecTests.cs b/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecTests.cs index b6448a7f374..a1407a92d34 100644 --- a/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecTests.cs +++ b/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecTests.cs @@ -10,7 +10,6 @@ using NuGet.Configuration; using NuGet.Frameworks; using NuGet.LibraryModel; -using NuGet.Packaging.Core; using NuGet.RuntimeModel; using NuGet.Versioning; using Xunit; @@ -18,114 +17,7 @@ namespace NuGet.ProjectModel.Test { public class PackageSpecTests - { - private BuildOptions CreateBuildOptions() - { - var outputName = "OutputName"; - var originalBuildOptions = new BuildOptions(); - originalBuildOptions.OutputName = outputName; - return originalBuildOptions; - } - - [Fact] - public void BuildOptionsCloneTest() - { - //Set up - var originalBuildOptions = CreateBuildOptions(); - - // Act - var clonedBuildOptions = originalBuildOptions.Clone(); - - //Assert - Assert.Equal(originalBuildOptions.OutputName, clonedBuildOptions.OutputName); - Assert.False(object.ReferenceEquals(originalBuildOptions, clonedBuildOptions)); - } - - [Fact] - public void IncludeExcludeFilesCloneTest() - { - //Set up - var exclude = new List() { "Exlclude0" }; - var include = new List() { "Include0" }; - var includeFiles = new List() { "IncludeFiles0" }; - var excludeFiles = new List() { "ExlcludeFiles0" }; - - var files = new IncludeExcludeFiles(); - files.Exclude = exclude; - files.Include = include; - files.IncludeFiles = includeFiles; - files.ExcludeFiles = excludeFiles; - - // Act - var clone = files.Clone(); - //Assert - - Assert.Equal(files.Exclude, clone.Exclude); - Assert.Equal(files.Include, clone.Include); - Assert.Equal(files.IncludeFiles, clone.IncludeFiles); - Assert.Equal(files.ExcludeFiles, clone.ExcludeFiles); - - // Act again - exclude.Add("Extra Exclude"); - - //Assert - Assert.Equal(2, files.Exclude.Count); - Assert.NotEqual(files.Exclude, clone.Exclude); - } - - [Fact] - public void PackOptionsCloneTest() - { - //Set up - var originalPackOptions = new PackOptions(); - var originalPackageName = "PackageA"; - var packageTypes = new List() { new Packaging.Core.PackageType(originalPackageName, new System.Version("1.0.0")) }; - - var exclude = new List() { "Exlclude0" }; - var include = new List() { "Include0" }; - var includeFiles = new List() { "IncludeFiles0" }; - var excludeFiles = new List() { "ExlcludeFiles0" }; - - var files = new IncludeExcludeFiles(); - files.Exclude = exclude; - files.Include = include; - files.IncludeFiles = includeFiles; - files.ExcludeFiles = excludeFiles; - - originalPackOptions.PackageType = packageTypes; - originalPackOptions.IncludeExcludeFiles = files; - - // Act - var clone = originalPackOptions.Clone(); - - // Assert - Assert.Equal(originalPackOptions, clone); - - // Act again - packageTypes.Clear(); - - // Assert - Assert.NotEqual(originalPackOptions, clone); - Assert.Equal(originalPackageName, clone.PackageType[0].Name); - - // Arrange again - originalPackOptions.Mappings.Add("randomString", files); - - // Act again - var cloneWithMappings = originalPackOptions.Clone(); - - // Assert - Assert.Equal(originalPackOptions, cloneWithMappings); - - // Act again - originalPackOptions.Mappings.Clear(); - - // Assert - Assert.NotEqual(originalPackOptions, cloneWithMappings); - Assert.Equal(1, cloneWithMappings.Mappings.Count); - } - internal static LibraryDependency CreateLibraryDependency() { var dependency = new LibraryDependency( @@ -143,26 +35,6 @@ internal static LibraryDependency CreateLibraryDependency() return dependency; } - [Obsolete] - private IncludeExcludeFiles CreateIncludeExcludeFiles() - { - var files = new IncludeExcludeFiles(); - files.Exclude = new List() { "Exlclude0" }; - files.Include = new List() { "Include0" }; - files.IncludeFiles = new List() { "IncludeFiles0" }; - files.ExcludeFiles = new List() { "ExlcludeFiles0" }; - return files; - } - - [Obsolete] - private PackOptions CreatePackOptions() - { - var originalPackOptions = new PackOptions(); - originalPackOptions.PackageType = new List() { new PackageType("PackageA", new Version("1.0.0")) }; - originalPackOptions.IncludeExcludeFiles = CreateIncludeExcludeFiles(); - return originalPackOptions; - } - private PackageSpec CreatePackageSpec() { var originalTargetFrameworkInformation = CreateTargetFrameworkInformation(); @@ -170,33 +42,7 @@ private PackageSpec CreatePackageSpec() packageSpec.RestoreMetadata = CreateProjectRestoreMetadata(); packageSpec.FilePath = "FilePath"; packageSpec.Name = "Name"; - packageSpec.Title = "Title"; packageSpec.Version = new NuGetVersion("1.0.0"); -#pragma warning disable CS0612 // Type or member is obsolete - packageSpec.HasVersionSnapshot = true; - packageSpec.Description = "Description"; - packageSpec.Summary = "Summary"; - packageSpec.ReleaseNotes = "ReleaseNotes"; - packageSpec.Authors = new string[] { "Author1" }; - packageSpec.Owners = new string[] { "Owner1" }; - packageSpec.ProjectUrl = "ProjectUrl"; - packageSpec.IconUrl = "IconUrl"; - packageSpec.LicenseUrl = "LicenseUrl"; - packageSpec.Copyright = "Copyright"; - packageSpec.Language = "Language"; - packageSpec.RequireLicenseAcceptance = true; - packageSpec.Tags = new string[] { "Tags" }; - packageSpec.BuildOptions = CreateBuildOptions(); - packageSpec.ContentFiles = new List() { "contentFile1", "contentFile2" }; - - packageSpec.Scripts.Add(Guid.NewGuid().ToString(), new List() { Guid.NewGuid().ToString() }); - packageSpec.Scripts.Add(Guid.NewGuid().ToString(), new List() { Guid.NewGuid().ToString() }); - - packageSpec.PackInclude.Add(Guid.NewGuid().ToString(), Guid.NewGuid().ToString()); - - packageSpec.PackOptions = CreatePackOptions(); -#pragma warning restore CS0612 // Type or member is obsolete - packageSpec.Dependencies = new List() { CreateLibraryDependency(), CreateLibraryDependency() }; packageSpec.RuntimeGraph = CreateRuntimeGraph(); packageSpec.RestoreSettings = CreateProjectRestoreSettings(); @@ -211,20 +57,11 @@ public static RuntimeGraph CreateRuntimeGraph() } [Theory] - [InlineData("ModifyAuthors", true)] [InlineData("ModifyOriginalTargetFrameworkInformationAdd", true)] [InlineData("ModifyOriginalTargetFrameworkInformationEdit", true)] [InlineData("ModifyRestoreMetadata", true)] [InlineData("ModifyVersion", true)] - [InlineData("ModifyOwners", true)] - [InlineData("ModifyTags", true)] - [InlineData("ModifyBuildOptions", false)] - [InlineData("ModifyContentFiles", true)] [InlineData("ModifyDependencies", true)] - [InlineData("ModifyScriptsAdd", true)] - [InlineData("ModifyScriptsEdit", true)] - [InlineData("ModifyPackInclude", true)] - [InlineData("ModifyPackOptions", true)] [InlineData("ModifyRuntimeGraph", true)] //[InlineData("ModifyRestoreSettings", true)] = Not really included in the equals and hash code comparisons public void PackageSpecCloneTest(string methodName, bool validateJson) @@ -262,12 +99,6 @@ public void PackageSpecCloneTest(string methodName, bool validateJson) public class PackageSpecModify { - [Obsolete] - public static void ModifyAuthors(PackageSpec packageSpec) - { - packageSpec.Authors[0] = "NewAuthor"; - } - public static void ModifyOriginalTargetFrameworkInformationAdd(PackageSpec packageSpec) { packageSpec.TargetFrameworks.Add(CreateTargetFrameworkInformation("net40")); @@ -287,65 +118,13 @@ public static void ModifyRestoreMetadata(PackageSpec packageSpec) public static void ModifyVersion(PackageSpec packageSpec) { - packageSpec.Version = new Versioning.NuGetVersion("2.0.0"); - } - - [Obsolete] - public static void ModifyOwners(PackageSpec packageSpec) - { - packageSpec.Owners[0] = "BetterOwner"; - } - - [Obsolete] - public static void ModifyTags(PackageSpec packageSpec) - { - packageSpec.Tags[0] = "better tag!"; - } - - [Obsolete] - public static void ModifyBuildOptions(PackageSpec packageSpec) - { - packageSpec.BuildOptions.OutputName = Guid.NewGuid().ToString(); - } - - [Obsolete] - public static void ModifyContentFiles(PackageSpec packageSpec) - { - packageSpec.ContentFiles.Add("New fnacy content file"); + packageSpec.Version = new NuGetVersion("2.0.0"); } public static void ModifyDependencies(PackageSpec packageSpec) { packageSpec.Dependencies.Add(CreateLibraryDependency()); } - - [Obsolete] - public static void ModifyScriptsAdd(PackageSpec packageSpec) - { - packageSpec.Scripts.Add(Guid.NewGuid().ToString(), new List() { Guid.NewGuid().ToString() }); - } - - [Obsolete] - public static void ModifyScriptsEdit(PackageSpec packageSpec) - { - var enumerator = packageSpec.Scripts.Keys.GetEnumerator(); - enumerator.MoveNext(); - var key = enumerator.Current; - ((List)packageSpec.Scripts[key]).Add(Guid.NewGuid().ToString()); - } - - [Obsolete] - public static void ModifyPackInclude(PackageSpec packageSpec) - { - packageSpec.PackInclude.Add(Guid.NewGuid().ToString(), Guid.NewGuid().ToString()); - } - - [Obsolete] - public static void ModifyPackOptions(PackageSpec packageSpec) - { - ((List)packageSpec.PackOptions.PackageType).Add(PackageType.DotnetCliTool); - } - public static void ModifyRuntimeGraph(PackageSpec packageSpec) { packageSpec.RuntimeGraph.Supports["CompatibilityProfile"].RestoreContexts.Add(CreateFrameworkRuntimePair(rid: "win10-x64")); @@ -902,25 +681,6 @@ public void CompatibilityProfileCloneTest() Assert.Equal(2, clone.RestoreContexts.Count); } - [Obsolete] - [Theory] - [InlineData(true)] - [InlineData(false)] - public void Clone_WhenIsDefaultVersionVaries_ReturnsEqualClone(bool expectedResult) - { - var packageSpec = new PackageSpec(); - - packageSpec.IsDefaultVersion = expectedResult; - - Assert.Equal(expectedResult, packageSpec.IsDefaultVersion); - - PackageSpec clone = packageSpec.Clone(); - - Assert.Equal(expectedResult, packageSpec.IsDefaultVersion); - Assert.Equal(expectedResult, clone.IsDefaultVersion); - Assert.True(packageSpec.Equals(clone)); - } - [Fact] public void PackageSpec_Equals_WithTargetFrameworkInformationOutOfOrder_ReturnsTrue() { diff --git a/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecWriterTests.cs b/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecWriterTests.cs index 78781eb57b1..6916a48cd38 100644 --- a/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecWriterTests.cs +++ b/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/PackageSpecWriterTests.cs @@ -98,38 +98,7 @@ public void Write_ReadWriteDependencies() { // Arrange var json = @"{ - ""title"": ""My Title"", ""version"": ""1.2.3"", - ""description"": ""test"", - ""authors"": [ - ""author1"", - ""author2"" - ], - ""copyright"": ""2016"", - ""language"": ""en-US"", - ""packInclude"": { - ""file"": ""file.txt"" - }, - ""packOptions"": { - ""owners"": [ - ""owner1"", - ""owner2"" - ], - ""tags"": [ - ""tag1"", - ""tag2"" - ], - ""projectUrl"": ""http://my.url.com"", - ""iconUrl"": ""http://my.url.com"", - ""summary"": ""Sum"", - ""releaseNotes"": ""release noted"", - ""licenseUrl"": ""http://my.url.com"" - }, - ""scripts"": { - ""script1"": [ - ""script.js"" - ] - }, ""dependencies"": { ""packageA"": { ""suppressParent"": ""All"", @@ -144,37 +113,6 @@ public void Write_ReadWriteDependencies() VerifyJsonPackageSpecRoundTrip(json); } - [Fact] - public void Write_ReadWriteSinglePackageType() - { - // Arrange - var json = @"{ - ""packOptions"": { - ""packageType"": ""DotNetTool"" - } -}"; - - // Act & Assert - VerifyJsonPackageSpecRoundTrip(json); - } - - [Fact] - public void Write_ReadWriteMultiplePackageType() - { - // Arrange - var json = @"{ - ""packOptions"": { - ""packageType"": [ - ""Dependency"", - ""DotNetTool"" - ] - } -}"; - - // Act & Assert - VerifyJsonPackageSpecRoundTrip(json); - } - [Fact] public void Write_ReadWriteWarningProperties() { @@ -275,7 +213,7 @@ public void Write_SerializesMembersAsJsonWithoutRestoreSettings() var actualJson = GetJsonString(packageSpec); // Assert - Assert.Equal(expectedJson, actualJson); + expectedJson.Should().Be(actualJson); } [Fact] @@ -890,35 +828,7 @@ private static PackageSpec CreatePackageSpec(bool withRestoreSettings, WarningPr var packageSpec = new PackageSpec() { -#pragma warning disable CS0612 // Type or member is obsolete - Authors = unsortedArray, - BuildOptions = new BuildOptions() { OutputName = "outputName" }, - ContentFiles = new List(unsortedArray), - Copyright = "copyright", Dependencies = new List() { libraryDependency, libraryDependencyWithNoWarnGlobal }, - Description = "description", - HasVersionSnapshot = true, - IconUrl = "iconUrl", - IsDefaultVersion = false, - Language = "language", - LicenseUrl = "licenseUrl", - Owners = unsortedArray, - PackOptions = new PackOptions() - { - IncludeExcludeFiles = new IncludeExcludeFiles() - { - Exclude = unsortedReadOnlyList, - ExcludeFiles = unsortedReadOnlyList, - Include = unsortedReadOnlyList, - IncludeFiles = unsortedReadOnlyList - } - }, - ProjectUrl = "projectUrl", - ReleaseNotes = "releaseNotes", - RequireLicenseAcceptance = true, - Summary = "summary", - Tags = unsortedArray, -#pragma warning restore CS0612 // Type or member is obsolete Name = "name", FilePath = "filePath", RestoreMetadata = new ProjectRestoreMetadata() @@ -944,7 +854,6 @@ private static PackageSpec CreatePackageSpec(bool withRestoreSettings, WarningPr new ProjectRestoreMetadataFrameworkInfo(nugetFramework) } }, - Title = "title", Version = new NuGetVersion("1.2.3") }; @@ -958,12 +867,6 @@ private static PackageSpec CreatePackageSpec(bool withRestoreSettings, WarningPr packageSpec.RestoreMetadata.ProjectWideWarningProperties = warningProperties; } -#pragma warning disable CS0612 // Type or member is obsolete - packageSpec.PackInclude.Add("b", "d"); - packageSpec.PackInclude.Add("a", "e"); - packageSpec.PackInclude.Add("c", "f"); -#pragma warning restore CS0612 // Type or member is obsolete - var runtimeDependencySet = new RuntimeDependencySet("id", new[] { new RuntimePackageDependency("id", new VersionRange(new NuGetVersion("1.2.3"))) @@ -979,12 +882,6 @@ private static PackageSpec CreatePackageSpec(bool withRestoreSettings, WarningPr packageSpec.RuntimeGraph = new RuntimeGraph(runtimes, compatibilityProfiles); -#pragma warning disable CS0612 // Type or member is obsolete - packageSpec.Scripts.Add("b", unsortedArray); - packageSpec.Scripts.Add("a", unsortedArray); - packageSpec.Scripts.Add("c", unsortedArray); -#pragma warning restore CS0612 // Type or member is obsolete - packageSpec.TargetFrameworks.Add(new TargetFrameworkInformation() { Dependencies = [], diff --git a/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/compiler/resources/PackageSpecWriter_Write_SerializesMembersAsJson.json b/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/compiler/resources/PackageSpecWriter_Write_SerializesMembersAsJson.json index 96ec2c5c311..6538822bdce 100644 --- a/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/compiler/resources/PackageSpecWriter_Write_SerializesMembersAsJson.json +++ b/src/nuget-client/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/compiler/resources/PackageSpecWriter_Write_SerializesMembersAsJson.json @@ -1,42 +1,5 @@ { - "title": "title", "version": "1.2.3", - "description": "description", - "authors": [ - "b", - "a", - "c" - ], - "copyright": "copyright", - "language": "language", - "contentFiles": [ - "b", - "a", - "c" - ], - "packInclude": { - "a": "e", - "b": "d", - "c": "f" - }, - "packOptions": { - "owners": [ - "b", - "a", - "c" - ], - "tags": [ - "b", - "a", - "c" - ], - "projectUrl": "projectUrl", - "iconUrl": "iconUrl", - "summary": "summary", - "releaseNotes": "releaseNotes", - "licenseUrl": "licenseUrl", - "requireLicenseAcceptance": true - }, "restore": { "projectUniqueName": "projectUniqueName", "projectName": "projectName", @@ -71,23 +34,6 @@ } } }, - "scripts": { - "a": [ - "b", - "a", - "c" - ], - "b": [ - "b", - "a", - "c" - ], - "c": [ - "b", - "a", - "c" - ] - }, "dependencies": { "library": { "include": "Build", diff --git a/src/nuget-client/test/NuGet.Core.Tests/NuGet.Protocol.Tests/Resources/PackageUpdateResourceTests.cs b/src/nuget-client/test/NuGet.Core.Tests/NuGet.Protocol.Tests/Resources/PackageUpdateResourceTests.cs index fab24207f51..4808c3e3502 100644 --- a/src/nuget-client/test/NuGet.Core.Tests/NuGet.Protocol.Tests/Resources/PackageUpdateResourceTests.cs +++ b/src/nuget-client/test/NuGet.Core.Tests/NuGet.Protocol.Tests/Resources/PackageUpdateResourceTests.cs @@ -9,6 +9,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using FluentAssertions; using NuGet.Common; using NuGet.Protocol.Core.Types; using NuGet.Test.Utility; @@ -515,6 +516,7 @@ await resource.Push( noServiceEndpoint: false, skipDuplicate: false, symbolPackageUpdateResource: null, + allowInsecureConnections: true, log: NullLogger.Instance); // Assert @@ -836,7 +838,7 @@ await resource.Push( [Theory] [InlineData(true, false)] [InlineData(false, true)] - public async Task Push_WithAnHttpSourceAndAllowInsecureConnections_NupkgOnly_Warns(bool allowInsecureConnections, bool isHttpWarningExpected) + public async Task Push_WithAnHttpSourceAndAllowInsecureConnections_NupkgOnly_Errors(bool allowInsecureConnections, bool isErrorExpected) { // Arrange using var workingDir = TestDirectory.Create(); @@ -873,14 +875,14 @@ await resource.Push( log: logger); // Assert - Assert.NotNull(sourceRequest); - if (isHttpWarningExpected) + if (isErrorExpected) { - Assert.Equal(1, logger.WarningMessages.Count); - Assert.Contains("You are running the 'push' operation with an 'HTTP' source", logger.WarningMessages.Single()); + Assert.Equal(1, logger.ErrorMessages.Count); + logger.ErrorMessages.Should().Contain(string.Format(Strings.Error_HttpServerUsage, "push", source)); } else { + Assert.NotNull(sourceRequest); Assert.Equal(0, logger.WarningMessages.Count); } @@ -889,7 +891,7 @@ await resource.Push( [Theory] [InlineData(true, false)] [InlineData(false, true)] - public async Task Push_WhenPushingToAnHttpSymbolSourceAndAllowInsecureConnections_Warns(bool allowInsecureConnections, bool isHttpWarningExpected) + public async Task Push_WhenPushingToAnHttpSymbolSourceAndAllowInsecureConnections_logsError(bool allowInsecureConnections, bool isErrorExpected) { // Arrange using var workingDir = TestDirectory.Create(); @@ -941,15 +943,15 @@ await resource.Push( log: logger); // Assert - Assert.NotNull(sourceRequest); - Assert.NotNull(symbolRequest); - if (isHttpWarningExpected) + if (isErrorExpected) { - Assert.Equal(1, logger.WarningMessages.Count); - Assert.Contains("You are running the 'push' operation with an 'HTTP' source", logger.WarningMessages.Single()); + Assert.Equal(1, logger.ErrorMessages.Count); + logger.ErrorMessages.Should().Contain(string.Format(Strings.Error_HttpServerUsage, "push", "http://other.smbsrc.net/api/v2/package/")); } else { + Assert.NotNull(sourceRequest); + Assert.NotNull(symbolRequest); Assert.Equal(0, logger.WarningMessages.Count); } } @@ -957,7 +959,7 @@ await resource.Push( [Theory] [InlineData(true, false)] [InlineData(false, true)] - public async Task Push_WhenPushingToAnHttpSourceAndSymbolSourceWithAllowInsecureConnections_WarnsForBoth(bool allowInsecureConnections, bool isHttpWarningExpected) + public async Task Push_WhenPushingToAnHttpSourceAndSymbolSourceWithAllowInsecureConnections_ErrorsForOne(bool allowInsecureConnections, bool isErrorExpected) { // Arrange using var workingDir = TestDirectory.Create(); @@ -1009,27 +1011,26 @@ await resource.Push( log: logger); // Assert - Assert.NotNull(sourceRequest); - Assert.NotNull(symbolRequest); - if (isHttpWarningExpected) + if (isErrorExpected) { - Assert.Equal(2, logger.WarningMessages.Count); - Assert.Contains("You are running the 'push' operation with an 'HTTP' source, 'http://www.nuget.org/api/v2/'. Non-HTTPS access will be removed in a future version. Consider migrating to an 'HTTPS' source.", logger.WarningMessages.First()); - Assert.Contains("You are running the 'push' operation with an 'HTTP' source, 'http://other.smbsrc.net/api/v2/package/'. Non-HTTPS access will be removed in a future version. Consider migrating to an 'HTTPS' source.", logger.WarningMessages.Last()); + Assert.Equal(1, logger.ErrorMessages.Count); + logger.ErrorMessages.Should().Contain(string.Format(Strings.Error_HttpServerUsage, "push", source)); } else { + Assert.NotNull(sourceRequest); + Assert.NotNull(symbolRequest); Assert.Equal(0, logger.WarningMessages.Count); } } [Fact] - public async Task Delete_WhenDeletingFromHTTPSource_Warns() + public async Task Delete_WhenDeletingFromHTTPSource_LogsAnError() { // Arrange using (var workingDir = TestDirectory.Create()) { - var source = "http://www.nuget.org/api/v2"; + var source = "http://www.nuget.org/api/v2/"; HttpRequestMessage actualRequest = null; var responses = new Dictionary>> { @@ -1058,10 +1059,8 @@ await resource.Delete( log: logger); // Assert - Assert.NotNull(actualRequest); - Assert.Equal(HttpMethod.Delete, actualRequest.Method); - Assert.Equal(3, logger.WarningMessages.Count); - Assert.Contains("You are running the 'delete' operation with an 'HTTP' source, 'http://www.nuget.org/api/v2/'. Non-HTTPS access will be removed in a future version. Consider migrating to an 'HTTPS' source.", logger.WarningMessages.Last()); + Assert.Equal(1, logger.Errors); + logger.ErrorMessages.Should().Contain(string.Format(Strings.Error_HttpServerUsage, "delete", source)); } } } diff --git a/src/razor/eng/Version.Details.xml b/src/razor/eng/Version.Details.xml index 386c93da8ec..91778b33dcf 100644 --- a/src/razor/eng/Version.Details.xml +++ b/src/razor/eng/Version.Details.xml @@ -8,99 +8,99 @@ 19eb5ea4e5f9c4e5256843a92805c8c9e942207d - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 - + https://github.com/dotnet/roslyn - 05e49aa98995349ffa26a19020333293ffe99670 + ded867328249b5a9b9e6e29e3f07abc19111f5d1 diff --git a/src/razor/eng/Versions.props b/src/razor/eng/Versions.props index 1fce8cbe21c..b8fbe4e25b3 100644 --- a/src/razor/eng/Versions.props +++ b/src/razor/eng/Versions.props @@ -47,31 +47,31 @@ --> - 3.12.0-beta1.25222.12 + 3.12.0-beta1.25230.6 9.0.0-alpha.1.25223.3 9.0.0-beta.25208.6 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 - 5.0.0-1.25222.12 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 + 5.0.0-1.25230.6 """; - await VerifySemanticTokensAsync(documentText, precise); + await VerifySemanticTokensAsync(documentText, precise, supportsVSExtensions: supportsVSExtensions); } [Theory] [CombinatorialData] - public async Task GetSemanticTokens_CSharp_VSCodeWorks(bool precise) + public async Task GetSemanticTokens_CSharp_VSCodeWorks(bool precise, bool supportsVSExtensions) { var documentText = """ @addTagHelper *, TestAssembly @@ -107,12 +107,12 @@ public async Task GetSemanticTokens_CSharp_VSCodeWorks(bool precise) """; var csharpTokens = new ProvideSemanticTokensResponse(tokens: [], hostDocumentSyncVersion: 1); - await AssertSemanticTokensAsync(documentText, precise, csharpTokens: csharpTokens, documentVersion: 1); + await AssertSemanticTokensAsync(documentText, precise, supportsVSExtensions: supportsVSExtensions, csharpTokens: csharpTokens, documentVersion: 1); } [Theory] [CombinatorialData] - public async Task GetSemanticTokens_CSharp_Explicit(bool precise) + public async Task GetSemanticTokens_CSharp_Explicit(bool precise, bool supportsVSExtensions) { var documentText = """ @using System @@ -120,12 +120,29 @@ @using System @(DateTime.Now) """; - await VerifySemanticTokensAsync(documentText, precise); + await VerifySemanticTokensAsync(documentText, precise, supportsVSExtensions: supportsVSExtensions); } [Theory] [CombinatorialData] - public async Task GetSemanticTokens_CSharp_Implicit(bool serverSupportsPreciseRanges, bool precise) + public async Task GetSemanticTokens_CSharp_Attribute(bool precise, bool supportsVSExtensions) + { + var documentText = """ + @using System.Diagnostics + @code { + [DebuggerDisplay($"{GetDebuggerDisplay,nq}")] + public class MyClass + { + } + } + """; + + await VerifySemanticTokensAsync(documentText, precise, isRazorFile: true, supportsVSExtensions: supportsVSExtensions); + } + + [Theory] + [CombinatorialData] + public async Task GetSemanticTokens_CSharp_Implicit(bool serverSupportsPreciseRanges, bool precise, bool supportsVSExtensions) { var documentText = """ @addTagHelper *, TestAssembly @@ -133,40 +150,40 @@ public async Task GetSemanticTokens_CSharp_Implicit(bool serverSupportsPreciseRa @d """; - var csharpTokens = await GetCSharpSemanticTokensResponseAsync(documentText, precise); - await AssertSemanticTokensAsync(documentText, precise, csharpTokens: csharpTokens, serverSupportsPreciseRanges: serverSupportsPreciseRanges); + var csharpTokens = await GetCSharpSemanticTokensResponseAsync(documentText, precise, supportsVSExtensions: supportsVSExtensions); + await AssertSemanticTokensAsync(documentText, precise, supportsVSExtensions: supportsVSExtensions, csharpTokens: csharpTokens, serverSupportsPreciseRanges: serverSupportsPreciseRanges); VerifyTimesLanguageServerCalled(serverSupportsPreciseRanges, precise); } [Theory] [CombinatorialData] - public async Task GetSemanticTokens_CSharp_VersionMismatch(bool serverSupportsPreciseRanges, bool precise) + public async Task GetSemanticTokens_CSharp_VersionMismatch(bool serverSupportsPreciseRanges, bool precise, bool supportsVSExtensions) { var documentText = """ @addTagHelper *, TestAssembly @{ var d = } """; - var csharpTokens = await GetCSharpSemanticTokensResponseAsync(documentText, precise); + var csharpTokens = await GetCSharpSemanticTokensResponseAsync(documentText, precise, supportsVSExtensions: supportsVSExtensions); await AssertSemanticTokensAsync(documentText, precise, csharpTokens: csharpTokens, documentVersion: 21, serverSupportsPreciseRanges: serverSupportsPreciseRanges); VerifyTimesLanguageServerCalled(serverSupportsPreciseRanges, precise); } [Theory] [CombinatorialData] - public async Task GetSemanticTokens_CSharp_FunctionAsync(bool precise) + public async Task GetSemanticTokens_CSharp_FunctionAsync(bool precise, bool supportsVSExtensions) { var documentText = """ @addTagHelper *, TestAssembly @{ var d = } """; - await VerifySemanticTokensAsync(documentText, precise); + await VerifySemanticTokensAsync(documentText, precise, supportsVSExtensions: supportsVSExtensions); } [Theory] [CombinatorialData] - public async Task GetSemanticTokens_CSharp_StaticModifier(bool precise) + public async Task GetSemanticTokens_CSharp_StaticModifier(bool precise, bool supportsVSExtensions) { var documentText = """ @code @@ -175,12 +192,12 @@ public async Task GetSemanticTokens_CSharp_StaticModifier(bool precise) } """; - await VerifySemanticTokensAsync(documentText, precise, isRazorFile: true); + await VerifySemanticTokensAsync(documentText, precise, supportsVSExtensions: supportsVSExtensions, isRazorFile: true); } [Theory] [CombinatorialData] - public async Task GetSemanticTokens_MultipleBlankLines(bool precise) + public async Task GetSemanticTokens_MultipleBlankLines(bool precise, bool supportsVSExtensions) { var documentText = """ @addTagHelper *, TestAssembly @@ -189,178 +206,178 @@ public async Task GetSemanticTokens_MultipleBlankLines(bool precise) second

"""; - await VerifySemanticTokensAsync(documentText, precise); + await VerifySemanticTokensAsync(documentText, precise, supportsVSExtensions: supportsVSExtensions); } [Theory] [CombinatorialData] - public async Task GetSemanticTokens_IncompleteTag(bool precise) + public async Task GetSemanticTokens_IncompleteTag(bool precise, bool supportsVSExtensions) { var documentText = """ """; - await VerifySemanticTokensAsync(documentText, precise); + await VerifySemanticTokensAsync(documentText, precise, supportsVSExtensions: supportsVSExtensions); } [Theory] [CombinatorialData] - public async Task GetSemanticTokens_PartialHTMLCommentAsync(bool precise) + public async Task GetSemanticTokens_PartialHTMLCommentAsync(bool precise, bool supportsVSExtensions) { var documentText = """ @addTagHelper *, TestAssembly ] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_RazorIfNotReady_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_RazorIfNotReady_VSCode.semantic.txt new file mode 100644 index 00000000000..364cfc9e436 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_RazorIfNotReady_VSCode.semantic.txt @@ -0,0 +1,11 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 markupTagDelimiter 0 [<] +0 1 1 markupElement 0 [p] +0 1 1 markupTagDelimiter 0 [>] +0 1 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 1 markupElement 0 [p] +0 1 1 markupTagDelimiter 0 [>] +0 1 1 razorTransition 0 [@] +0 1 1 razorTransition 0 [{] +2 0 1 razorTransition 0 [}] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_StaticModifier_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_StaticModifier_VSCode.semantic.txt new file mode 100644 index 00000000000..793f6d11273 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_StaticModifier_VSCode.semantic.txt @@ -0,0 +1,11 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 4 razorDirective 0 [code] +1 0 1 razorTransition 0 [{] +1 4 6 keyword 0 [static] +0 7 3 keyword 0 [int] +0 4 1 field 1 [x] +0 2 1 operator 0 [=] +0 2 1 number 0 [1] +0 1 1 punctuation 0 [;] +1 0 1 razorTransition 0 [}] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_Static_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_Static_VSCode.semantic.txt new file mode 100644 index 00000000000..2edd45d94c8 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_Static_VSCode.semantic.txt @@ -0,0 +1,26 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 5 keyword 0 [using] +0 6 6 namespace 0 [System] +1 0 1 razorTransition 0 [@] +0 1 4 razorDirective 0 [code] +1 0 1 razorTransition 0 [{] +1 4 7 keyword 0 [private] +0 8 6 keyword 0 [static] +0 7 4 keyword 0 [bool] +0 5 9 field 1 [_isStatic] +0 9 1 punctuation 0 [;] +2 4 6 keyword 0 [public] +0 7 4 keyword 0 [void] +0 5 1 method 0 [M] +0 1 1 punctuation 0 [(] +0 1 1 punctuation 0 [)] +1 4 1 punctuation 0 [{] +1 8 2 controlKeyword 0 [if] +0 3 1 punctuation 0 [(] +0 1 9 field 1 [_isStatic] +0 9 1 punctuation 0 [)] +1 8 1 punctuation 0 [{] +1 8 1 punctuation 0 [}] +1 4 1 punctuation 0 [}] +1 0 1 razorTransition 0 [}] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_Static_WithBackground_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_Static_WithBackground_VSCode.semantic.txt new file mode 100644 index 00000000000..6fcdbf5dc50 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_Static_WithBackground_VSCode.semantic.txt @@ -0,0 +1,40 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 5 keyword 8 [using] +0 5 1 markupTextLiteral 8 [ ] +0 1 6 namespace 8 [System] +1 0 1 razorTransition 0 [@] +0 1 4 razorDirective 0 [code] +1 0 1 razorTransition 0 [{] +1 0 4 markupTextLiteral 8 [ ] +0 4 7 keyword 8 [private] +0 7 1 markupTextLiteral 8 [ ] +0 1 6 keyword 8 [static] +0 6 1 markupTextLiteral 8 [ ] +0 1 4 keyword 8 [bool] +1 0 8 markupTextLiteral 8 [ ] +0 8 9 field 9 [_isStatic] +0 9 1 punctuation 8 [;] +2 0 4 markupTextLiteral 8 [ ] +0 4 6 keyword 8 [public] +0 6 1 markupTextLiteral 8 [ ] +0 1 4 keyword 8 [void] +0 4 1 markupTextLiteral 8 [ ] +0 1 1 method 8 [M] +0 1 1 punctuation 8 [(] +0 1 1 punctuation 8 [)] +1 0 4 markupTextLiteral 8 [ ] +0 4 1 punctuation 8 [{] +1 0 8 markupTextLiteral 8 [ ] +0 8 2 controlKeyword 8 [if] +0 2 1 markupTextLiteral 8 [ ] +0 1 1 punctuation 8 [(] +0 1 9 field 9 [_isStatic] +0 9 1 punctuation 8 [)] +1 0 8 markupTextLiteral 8 [ ] +0 8 1 punctuation 8 [{] +1 0 8 markupTextLiteral 8 [ ] +0 8 1 punctuation 8 [}] +1 0 4 markupTextLiteral 8 [ ] +0 4 1 punctuation 8 [}] +1 0 1 razorTransition 0 [}] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_Tabs_Static_WithBackground_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_Tabs_Static_WithBackground_VSCode.semantic.txt new file mode 100644 index 00000000000..308324f551d --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_Tabs_Static_WithBackground_VSCode.semantic.txt @@ -0,0 +1,40 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 5 keyword 8 [using] +0 5 1 markupTextLiteral 8 [ ] +0 1 6 namespace 8 [System] +1 0 1 razorTransition 0 [@] +0 1 4 razorDirective 0 [code] +1 0 1 razorTransition 0 [{] +1 0 1 markupTextLiteral 8 [ ] +0 1 7 keyword 8 [private] +0 7 1 markupTextLiteral 8 [ ] +0 1 6 keyword 8 [static] +0 6 1 markupTextLiteral 8 [ ] +0 1 4 keyword 8 [bool] +1 0 2 markupTextLiteral 8 [ ] +0 2 9 field 9 [_isStatic] +0 9 1 punctuation 8 [;] +2 0 1 markupTextLiteral 8 [ ] +0 1 6 keyword 8 [public] +0 6 1 markupTextLiteral 8 [ ] +0 1 4 keyword 8 [void] +0 4 1 markupTextLiteral 8 [ ] +0 1 1 method 8 [M] +0 1 1 punctuation 8 [(] +0 1 1 punctuation 8 [)] +1 0 1 markupTextLiteral 8 [ ] +0 1 1 punctuation 8 [{] +1 0 2 markupTextLiteral 8 [ ] +0 2 2 controlKeyword 8 [if] +0 2 1 markupTextLiteral 8 [ ] +0 1 1 punctuation 8 [(] +0 1 9 field 9 [_isStatic] +0 9 1 punctuation 8 [)] +1 0 2 markupTextLiteral 8 [ ] +0 2 1 punctuation 8 [{] +1 0 2 markupTextLiteral 8 [ ] +0 2 1 punctuation 8 [}] +1 0 1 markupTextLiteral 8 [ ] +0 1 1 punctuation 8 [}] +1 0 1 razorTransition 0 [}] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_VSCodeWorks_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_VSCodeWorks_VSCode.semantic.txt new file mode 100644 index 00000000000..e61a88f1a95 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_VSCodeWorks_VSCode.semantic.txt @@ -0,0 +1,6 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] +1 0 1 razorTransition 0 [@] +0 1 1 razorTransition 0 [{] +0 10 1 razorTransition 0 [}] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_WitRenderFragmentAndBackground_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_WitRenderFragmentAndBackground_VSCode.semantic.txt new file mode 100644 index 00000000000..7333fbc1a76 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_WitRenderFragmentAndBackground_VSCode.semantic.txt @@ -0,0 +1,39 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 markupTagDelimiter 0 [<] +0 1 3 markupElement 0 [div] +0 3 1 markupTagDelimiter 0 [>] +0 18 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 3 markupElement 0 [div] +0 3 1 markupTagDelimiter 0 [>] +1 0 1 razorTransition 0 [@] +0 1 4 razorDirective 0 [code] +1 0 1 razorTransition 0 [{] +1 0 4 markupTextLiteral 8 [ ] +0 4 6 keyword 8 [public] +0 6 1 markupTextLiteral 8 [ ] +0 1 4 keyword 8 [void] +0 4 1 markupTextLiteral 8 [ ] +0 1 1 method 8 [M] +0 1 1 punctuation 8 [(] +0 1 1 punctuation 8 [)] +1 0 4 markupTextLiteral 8 [ ] +0 4 1 punctuation 8 [{] +1 0 8 markupTextLiteral 8 [ ] +0 8 14 variable 8 [RenderFragment] +0 14 1 markupTextLiteral 8 [ ] +0 1 1 variable 8 [x] +0 1 1 markupTextLiteral 8 [ ] +0 1 1 operator 8 [=] +0 2 1 razorTransition 8 [@] +0 1 1 markupTagDelimiter 0 [<] +0 1 3 markupElement 0 [div] +0 3 1 markupTagDelimiter 0 [>] +0 18 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 3 markupElement 0 [div] +0 3 1 markupTagDelimiter 0 [>] +0 1 1 punctuation 8 [;] +1 0 4 markupTextLiteral 8 [ ] +0 4 1 punctuation 8 [}] +1 0 1 razorTransition 0 [}] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_WitRenderFragment_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_WitRenderFragment_VSCode.semantic.txt new file mode 100644 index 00000000000..ca8d170236f --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_WitRenderFragment_VSCode.semantic.txt @@ -0,0 +1,31 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 markupTagDelimiter 0 [<] +0 1 3 markupElement 0 [div] +0 3 1 markupTagDelimiter 0 [>] +0 18 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 3 markupElement 0 [div] +0 3 1 markupTagDelimiter 0 [>] +1 0 1 razorTransition 0 [@] +0 1 4 razorDirective 0 [code] +1 0 1 razorTransition 0 [{] +1 4 6 keyword 0 [public] +0 7 4 keyword 0 [void] +0 5 1 method 0 [M] +0 1 1 punctuation 0 [(] +0 1 1 punctuation 0 [)] +1 4 1 punctuation 0 [{] +1 8 14 variable 0 [RenderFragment] +0 15 1 variable 0 [x] +0 2 1 operator 0 [=] +0 2 1 razorTransition 0 [@] +0 1 1 markupTagDelimiter 0 [<] +0 1 3 markupElement 0 [div] +0 3 1 markupTagDelimiter 0 [>] +0 18 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 3 markupElement 0 [div] +0 3 1 markupTagDelimiter 0 [>] +0 1 1 punctuation 0 [;] +1 4 1 punctuation 0 [}] +1 0 1 razorTransition 0 [}] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_WithBackground_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_WithBackground_VSCode.semantic.txt new file mode 100644 index 00000000000..0ba92f44ba1 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_CSharp_WithBackground_VSCode.semantic.txt @@ -0,0 +1,40 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 5 keyword 8 [using] +0 5 1 markupTextLiteral 8 [ ] +0 1 6 namespace 8 [System] +1 0 1 razorTransition 0 [@] +0 1 4 razorDirective 0 [code] +1 0 1 razorTransition 0 [{] +1 0 4 markupTextLiteral 8 [ ] +0 4 7 keyword 8 [private] +0 7 1 markupTextLiteral 8 [ ] +0 1 6 keyword 8 [static] +0 6 1 markupTextLiteral 8 [ ] +0 1 4 keyword 8 [bool] +0 4 1 markupTextLiteral 8 [ ] +0 1 9 field 9 [_isStatic] +0 9 1 punctuation 8 [;] +2 0 4 markupTextLiteral 8 [ ] +0 4 6 keyword 8 [public] +0 6 1 markupTextLiteral 8 [ ] +0 1 4 keyword 8 [void] +0 4 1 markupTextLiteral 8 [ ] +0 1 1 method 8 [M] +0 1 1 punctuation 8 [(] +0 1 1 punctuation 8 [)] +1 0 4 markupTextLiteral 8 [ ] +0 4 1 punctuation 8 [{] +1 0 8 markupTextLiteral 8 [ ] +0 8 2 controlKeyword 8 [if] +0 2 1 markupTextLiteral 8 [ ] +0 1 1 punctuation 8 [(] +0 1 9 field 9 [_isStatic] +0 9 1 punctuation 8 [)] +1 0 8 markupTextLiteral 8 [ ] +0 8 1 punctuation 8 [{] +1 0 8 markupTextLiteral 8 [ ] +0 8 1 punctuation 8 [}] +1 0 4 markupTextLiteral 8 [ ] +0 4 1 punctuation 8 [}] +1 0 1 razorTransition 0 [}] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_DoesNotApplyOnNonTagHelpersAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_DoesNotApplyOnNonTagHelpersAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..86eee2f5bb7 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_DoesNotApplyOnNonTagHelpersAsync_VSCode.semantic.txt @@ -0,0 +1,15 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] +1 0 1 markupTagDelimiter 0 [<] +0 1 1 markupElement 0 [p] +0 2 8 markupAttribute 0 [bool-val] +0 8 1 markupOperator 0 [=] +0 1 1 markupAttributeQuote 0 ['] +0 1 4 markupAttributeValue 0 [true] +0 4 1 markupAttributeQuote 0 ['] +0 1 1 markupTagDelimiter 0 [>] +0 1 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 1 markupElement 0 [p] +0 1 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_HTMLCommentAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_HTMLCommentAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..2e8d2d7e8bb --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_HTMLCommentAsync_VSCode.semantic.txt @@ -0,0 +1,6 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] +1 0 4 markupCommentPunctuation 0 [] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_HTMLIncludesBang_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_HTMLIncludesBang_VSCode.semantic.txt new file mode 100644 index 00000000000..0a80c3e679a --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_HTMLIncludesBang_VSCode.semantic.txt @@ -0,0 +1,8 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] +1 0 1 markupTagDelimiter 0 [<] +0 1 1 razorTransition 0 [!] +0 1 5 markupElement 0 [input] +0 5 1 markupTagDelimiter 0 [/] +0 1 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_HalfOfCommentAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_HalfOfCommentAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..853651e2121 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_HalfOfCommentAsync_VSCode.semantic.txt @@ -0,0 +1,6 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] +1 0 1 razorCommentTransition 0 [@] +0 1 1 razorCommentStar 0 [*] +0 1 8 razorComment 0 [ comment] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_HandleTransitionEscape_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_HandleTransitionEscape_VSCode.semantic.txt new file mode 100644 index 00000000000..6203cd4fb71 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_HandleTransitionEscape_VSCode.semantic.txt @@ -0,0 +1 @@ +//line,characterPos,length,tokenType,modifier,text diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_IgnoresNonTagHelperAttributesAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_IgnoresNonTagHelperAttributesAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..53ec634797c --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_IgnoresNonTagHelperAttributesAsync_VSCode.semantic.txt @@ -0,0 +1,20 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] +1 0 1 markupTagDelimiter 0 [<] +0 1 5 razorTagHelperElement 0 [test1] +0 6 8 razorTagHelperAttribute 0 [bool-val] +0 8 1 markupOperator 0 [=] +0 1 1 markupAttributeQuote 0 ['] +0 1 4 keyword 0 [true] +0 4 1 markupAttributeQuote 0 ['] +0 2 5 markupAttribute 0 [class] +0 5 1 markupOperator 0 [=] +0 1 1 markupAttributeQuote 0 ['] +0 1 12 markupAttributeValue 0 [display:none] +0 12 1 markupAttributeQuote 0 ['] +0 1 1 markupTagDelimiter 0 [>] +0 1 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 5 razorTagHelperElement 0 [test1] +0 5 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_IncompleteTag_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_IncompleteTag_VSCode.semantic.txt new file mode 100644 index 00000000000..c4bad0a367b --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_IncompleteTag_VSCode.semantic.txt @@ -0,0 +1,6 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 markupTagDelimiter 0 [<] +0 1 3 markupElement 0 [str] +0 4 5 markupAttribute 0 [class] +0 5 1 markupOperator 0 [=] +0 1 1 markupAttributeQuote 0 ['] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Legacy_Model_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Legacy_Model_VSCode.semantic.txt new file mode 100644 index 00000000000..14f2229b341 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Legacy_Model_VSCode.semantic.txt @@ -0,0 +1,28 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 5 keyword 0 [using] +0 6 6 namespace 0 [System] +1 0 1 razorTransition 0 [@] +0 1 5 razorDirective 0 [model] +0 6 9 variable 0 [SampleApp] +0 9 1 operator 0 [.] +0 1 5 variable 0 [Pages] +0 5 1 operator 0 [.] +0 1 10 variable 0 [ErrorModel] +2 0 1 markupTagDelimiter 0 [<] +0 1 3 markupElement 0 [div] +0 3 1 markupTagDelimiter 0 [>] +2 4 1 razorTransition 0 [@] +0 1 1 razorTransition 0 [{] +1 8 1 razorTransition 0 [@] +0 1 5 variable 0 [Model] +0 5 1 operator 0 [.] +0 1 8 variable 0 [ToString] +0 8 1 punctuation 0 [(] +0 1 1 punctuation 0 [)] +0 1 1 punctuation 0 [;] +1 4 1 razorTransition 0 [}] +2 0 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 3 markupElement 0 [div] +0 3 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_MinimizedAttribute_BoundAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_MinimizedAttribute_BoundAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..35e979cb7dd --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_MinimizedAttribute_BoundAsync_VSCode.semantic.txt @@ -0,0 +1,11 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] +1 0 1 markupTagDelimiter 0 [<] +0 1 5 razorTagHelperElement 0 [test1] +0 6 8 razorTagHelperAttribute 0 [bool-val] +0 8 1 markupTagDelimiter 0 [>] +0 1 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 5 razorTagHelperElement 0 [test1] +0 5 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_MinimizedAttribute_NotBoundAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_MinimizedAttribute_NotBoundAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..a87a2aaafb7 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_MinimizedAttribute_NotBoundAsync_VSCode.semantic.txt @@ -0,0 +1,11 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] +1 0 1 markupTagDelimiter 0 [<] +0 1 5 razorTagHelperElement 0 [test1] +0 6 8 markupAttribute 0 [notbound] +0 8 1 markupTagDelimiter 0 [>] +0 1 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 5 razorTagHelperElement 0 [test1] +0 5 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_MinimizedHTMLAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_MinimizedHTMLAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..43f24d077ac --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_MinimizedHTMLAsync_VSCode.semantic.txt @@ -0,0 +1,7 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] +1 0 1 markupTagDelimiter 0 [<] +0 1 5 markupElement 0 [input] +0 5 1 markupTagDelimiter 0 [/] +0 1 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_MinimizedHTMLAttribute_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_MinimizedHTMLAttribute_VSCode.semantic.txt new file mode 100644 index 00000000000..208cb0f92f0 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_MinimizedHTMLAttribute_VSCode.semantic.txt @@ -0,0 +1,6 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 markupTagDelimiter 0 [<] +0 1 1 markupElement 0 [p] +0 2 4 markupAttribute 0 [attr] +0 5 1 markupTagDelimiter 0 [/] +0 1 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_MultipleBlankLines_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_MultipleBlankLines_VSCode.semantic.txt new file mode 100644 index 00000000000..e9df1f411c3 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_MultipleBlankLines_VSCode.semantic.txt @@ -0,0 +1,10 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] +2 0 1 markupTagDelimiter 0 [<] +0 1 1 markupElement 0 [p] +0 1 1 markupTagDelimiter 0 [>] +1 6 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 1 markupElement 0 [p] +0 1 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_NoAttributesAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_NoAttributesAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..7351360238d --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_NoAttributesAsync_VSCode.semantic.txt @@ -0,0 +1,10 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] +1 0 1 markupTagDelimiter 0 [<] +0 1 5 razorTagHelperElement 0 [test1] +0 5 1 markupTagDelimiter 0 [>] +0 1 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 5 razorTagHelperElement 0 [test1] +0 5 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_PartialHTMLCommentAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_PartialHTMLCommentAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..c6d0db717e2 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_PartialHTMLCommentAsync_VSCode.semantic.txt @@ -0,0 +1,3 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_CodeDirectiveAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_CodeDirectiveAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..35b2563bc01 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_CodeDirectiveAsync_VSCode.semantic.txt @@ -0,0 +1,5 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 4 razorDirective 0 [code] +0 5 1 razorTransition 0 [{] +0 1 1 razorTransition 0 [}] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_CodeDirectiveBodyAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_CodeDirectiveBodyAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..2a9fa9c73bc --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_CodeDirectiveBodyAsync_VSCode.semantic.txt @@ -0,0 +1,19 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 5 keyword 0 [using] +0 6 6 namespace 0 [System] +1 0 1 razorTransition 0 [@] +0 1 4 razorDirective 0 [code] +0 5 1 razorTransition 0 [{] +1 4 6 keyword 0 [public] +0 7 4 keyword 0 [void] +0 5 10 method 0 [SomeMethod] +0 10 1 punctuation 0 [(] +0 1 1 punctuation 0 [)] +1 4 1 punctuation 0 [{] +1 8 1 razorTransition 0 [@] +0 1 8 struct 0 [DateTime] +0 8 1 operator 0 [.] +0 1 3 property 1 [Now] +1 4 1 punctuation 0 [}] +1 0 1 razorTransition 0 [}] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_CommentAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_CommentAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..d64cf567ff3 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_CommentAsync_VSCode.semantic.txt @@ -0,0 +1,6 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorCommentTransition 0 [@] +0 1 1 razorCommentStar 0 [*] +0 1 11 razorComment 0 [ A comment ] +0 11 1 razorCommentStar 0 [*] +0 1 1 razorCommentTransition 0 [@] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_ComponentAttributeAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_ComponentAttributeAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..5b294370d67 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_ComponentAttributeAsync_VSCode.semantic.txt @@ -0,0 +1,15 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] +1 0 1 markupTagDelimiter 0 [<] +0 1 10 razorComponentElement 0 [Component1] +0 11 8 razorComponentAttribute 0 [bool-val] +0 8 1 markupOperator 0 [=] +0 1 1 markupAttributeQuote 0 ["] +0 1 1 markupAttributeQuote 0 ["] +0 1 6 markupAttribute 0 [true""] +0 6 1 markupTagDelimiter 0 [>] +0 1 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 10 razorComponentElement 0 [Component1] +0 10 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_ComponentAttribute_DoesntGetABackground_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_ComponentAttribute_DoesntGetABackground_VSCode.semantic.txt new file mode 100644 index 00000000000..f42a101cd50 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_ComponentAttribute_DoesntGetABackground_VSCode.semantic.txt @@ -0,0 +1,25 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 8 [@] +0 1 8 variable 8 [DateTime] +0 8 1 operator 8 [.] +0 1 3 variable 8 [Now] +2 0 1 markupTagDelimiter 0 [<] +0 1 10 razorComponentElement 0 [Component1] +0 11 5 razorComponentAttribute 0 [Title] +0 5 1 markupOperator 0 [=] +0 1 1 markupAttributeQuote 0 ["] +0 1 1 markupAttributeQuote 0 ["] +0 1 2 markupAttribute 0 [Hi] +0 3 5 markupAttribute 0 [there] +0 6 3 markupAttribute 0 [I'm] +0 4 1 markupAttribute 0 [a] +0 2 8 markupAttribute 0 [string""] +0 8 1 markupTagDelimiter 0 [>] +0 1 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 10 razorComponentElement 0 [Component1] +0 10 1 markupTagDelimiter 0 [>] +2 0 1 razorTransition 8 [@] +0 1 8 variable 8 [DateTime] +0 8 1 operator 8 [.] +0 1 3 variable 8 [Now] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_DirectiveAttributesParametersAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_DirectiveAttributesParametersAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..a8ca28dfd59 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_DirectiveAttributesParametersAsync_VSCode.semantic.txt @@ -0,0 +1,18 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] +1 0 1 markupTagDelimiter 0 [<] +0 1 10 razorComponentElement 0 [Component1] +0 11 1 razorTransition 0 [@] +0 1 4 razorDirectiveAttribute 0 [test] +0 4 1 razorDirectiveColon 0 [:] +0 1 9 razorDirectiveAttribute 0 [something] +0 9 1 markupOperator 0 [=] +0 1 1 markupAttributeQuote 0 ['] +0 1 8 markupAttributeValue 0 [Function] +0 8 1 markupAttributeQuote 0 ['] +0 1 1 markupTagDelimiter 0 [>] +0 1 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 10 razorComponentElement 0 [Component1] +0 10 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_DirectiveWithExplicitStatementAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_DirectiveWithExplicitStatementAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..3681ce23641 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_DirectiveWithExplicitStatementAsync_VSCode.semantic.txt @@ -0,0 +1,21 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] +1 0 1 markupTagDelimiter 0 [<] +0 1 10 razorComponentElement 0 [Component1] +0 11 1 razorTransition 0 [@] +0 1 7 razorDirectiveAttribute 0 [onclick] +0 7 1 markupOperator 0 [=] +0 1 1 markupAttributeQuote 0 ["] +0 1 1 razorTransition 0 [@] +0 1 1 razorTransition 0 [(] +0 1 8 variable 0 [Function] +0 8 1 punctuation 0 [(] +0 1 1 punctuation 0 [)] +0 1 1 razorTransition 0 [)] +0 1 1 markupAttributeQuote 0 ["] +0 1 1 markupTagDelimiter 0 [>] +0 1 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 10 razorComponentElement 0 [Component1] +0 10 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_DirectivesAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_DirectivesAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..0697619cb03 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_DirectivesAsync_VSCode.semantic.txt @@ -0,0 +1,16 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] +1 0 1 markupTagDelimiter 0 [<] +0 1 10 razorComponentElement 0 [Component1] +0 11 1 razorTransition 0 [@] +0 1 4 razorDirectiveAttribute 0 [test] +0 4 1 markupOperator 0 [=] +0 1 1 markupAttributeQuote 0 ['] +0 1 8 markupAttributeValue 0 [Function] +0 8 1 markupAttributeQuote 0 ['] +0 1 1 markupTagDelimiter 0 [>] +0 1 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 10 razorComponentElement 0 [Component1] +0 10 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_DoNotColorNonTagHelpersAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_DoNotColorNonTagHelpersAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..8e5915ce08d --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_DoNotColorNonTagHelpersAsync_VSCode.semantic.txt @@ -0,0 +1,14 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 markupTagDelimiter 0 [<] +0 1 1 markupElement 0 [p] +0 2 1 razorTransition 0 [@] +0 1 4 razorDirectiveAttribute 0 [test] +0 4 1 markupOperator 0 [=] +0 1 1 markupAttributeQuote 0 ['] +0 1 8 markupAttributeValue 0 [Function] +0 8 1 markupAttributeQuote 0 ['] +0 1 1 markupTagDelimiter 0 [>] +0 1 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 1 markupElement 0 [p] +0 1 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_DoesNotApplyOnNonTagHelpersAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_DoesNotApplyOnNonTagHelpersAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..8388e25a4be --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_DoesNotApplyOnNonTagHelpersAsync_VSCode.semantic.txt @@ -0,0 +1,10 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 13 variable 0 [addTagHelpers] +1 0 1 markupTagDelimiter 0 [<] +0 1 1 markupElement 0 [p] +0 1 1 markupTagDelimiter 0 [>] +0 1 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 1 markupElement 0 [p] +0 1 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_FunctionsDirectiveAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_FunctionsDirectiveAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..654c78abedd --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_FunctionsDirectiveAsync_VSCode.semantic.txt @@ -0,0 +1,5 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 9 razorDirective 0 [functions] +0 10 1 razorTransition 0 [{] +0 1 1 razorTransition 0 [}] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_MinimizedDirectiveAttributeParameters_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_MinimizedDirectiveAttributeParameters_VSCode.semantic.txt new file mode 100644 index 00000000000..67b737da285 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_MinimizedDirectiveAttributeParameters_VSCode.semantic.txt @@ -0,0 +1,11 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] +1 1 1 markupTagDelimiter 0 [<] +0 1 11 markupElement 0 [NotATagHelp] +0 12 1 razorTransition 0 [@] +0 1 9 razorDirectiveAttribute 0 [minimized] +0 9 1 razorDirectiveColon 0 [:] +0 1 9 razorDirectiveAttribute 0 [something] +0 10 1 markupTagDelimiter 0 [/] +0 1 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_MultiLineCommentAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_MultiLineCommentAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..4810ae5485d --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_MultiLineCommentAsync_VSCode.semantic.txt @@ -0,0 +1,7 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorCommentTransition 0 [@] +0 1 1 razorCommentStar 0 [*] +0 1 5 razorComment 0 [stuff] +1 0 7 razorComment 0 [things ] +0 7 1 razorCommentStar 0 [*] +0 1 1 razorCommentTransition 0 [@] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_MultiLineCommentMidlineAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_MultiLineCommentMidlineAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..bba8bd5acd3 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_MultiLineCommentMidlineAsync_VSCode.semantic.txt @@ -0,0 +1,12 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 markupTagDelimiter 0 [<] +0 1 1 markupElement 0 [a] +0 2 1 markupTagDelimiter 0 [/] +0 1 1 markupTagDelimiter 0 [>] +0 1 1 razorCommentTransition 0 [@] +0 1 1 razorCommentStar 0 [*] +0 1 4 razorComment 0 [ kdl] +1 0 3 razorComment 0 [skd] +1 0 3 razorComment 0 [slf] +0 3 1 razorCommentStar 0 [*] +0 1 1 razorCommentTransition 0 [@] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_MultiLineCommentWithBlankLines_LF_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_MultiLineCommentWithBlankLines_LF_VSCode.semantic.txt new file mode 100644 index 00000000000..d9493f76168 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_MultiLineCommentWithBlankLines_LF_VSCode.semantic.txt @@ -0,0 +1,10 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorCommentTransition 0 [@] +0 1 1 razorCommentStar 0 [*] +0 1 4 razorComment 0 [ kdl] +2 0 3 razorComment 0 [skd] +1 0 4 razorComment 0 [ ] +1 0 19 razorComment 0 [ sdfasdfasdf] +1 0 3 razorComment 0 [slf] +0 3 1 razorCommentStar 0 [*] +0 1 1 razorCommentTransition 0 [@] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_MultiLineCommentWithBlankLines_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_MultiLineCommentWithBlankLines_VSCode.semantic.txt new file mode 100644 index 00000000000..d9493f76168 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_MultiLineCommentWithBlankLines_VSCode.semantic.txt @@ -0,0 +1,10 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorCommentTransition 0 [@] +0 1 1 razorCommentStar 0 [*] +0 1 4 razorComment 0 [ kdl] +2 0 3 razorComment 0 [skd] +1 0 4 razorComment 0 [ ] +1 0 19 razorComment 0 [ sdfasdfasdf] +1 0 3 razorComment 0 [slf] +0 3 1 razorCommentStar 0 [*] +0 1 1 razorCommentTransition 0 [@] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_NestedTextDirectives_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_NestedTextDirectives_VSCode.semantic.txt new file mode 100644 index 00000000000..a6e02079ae2 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_NestedTextDirectives_VSCode.semantic.txt @@ -0,0 +1,55 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 5 keyword 0 [using] +0 6 6 namespace 0 [System] +1 0 1 razorTransition 0 [@] +0 1 9 razorDirective 0 [functions] +0 10 1 razorTransition 0 [{] +1 4 7 keyword 0 [private] +0 8 4 keyword 0 [void] +0 5 14 method 0 [BidsByShipment] +0 14 1 punctuation 0 [(] +0 1 6 keyword 0 [string] +0 7 11 parameter 0 [generatedId] +0 11 1 punctuation 0 [,] +0 2 3 keyword 0 [int] +0 4 4 parameter 0 [bids] +0 4 1 punctuation 0 [)] +1 4 1 punctuation 0 [{] +1 8 2 controlKeyword 0 [if] +0 3 1 punctuation 0 [(] +0 1 4 parameter 0 [bids] +0 5 1 operator 0 [>] +0 2 1 number 0 [0] +0 1 1 punctuation 0 [)] +1 8 1 punctuation 0 [{] +1 12 1 markupTagDelimiter 0 [<] +0 1 1 markupElement 0 [a] +0 2 5 markupAttribute 0 [class] +0 5 1 markupOperator 0 [=] +0 1 1 markupAttributeQuote 0 ["] +0 1 1 markupAttributeQuote 0 ["] +0 1 7 markupAttribute 0 [Thing""] +0 7 1 markupTagDelimiter 0 [>] +1 16 1 razorTransition 0 [@] +0 1 2 controlKeyword 0 [if] +0 2 1 punctuation 0 [(] +0 1 4 parameter 0 [bids] +0 5 1 operator 0 [>] +0 2 1 number 0 [0] +0 1 1 punctuation 0 [)] +1 16 1 punctuation 0 [{] +1 20 6 razorDirective 0 [] +0 6 1 razorTransition 0 [@] +0 1 8 struct 0 [DateTime] +0 8 1 operator 0 [.] +0 1 3 property 1 [Now] +0 3 7 razorDirective 0 [] +1 16 1 punctuation 0 [}] +1 12 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 1 markupElement 0 [a] +0 1 1 markupTagDelimiter 0 [>] +1 8 1 punctuation 0 [}] +1 4 1 punctuation 0 [}] +1 0 1 razorTransition 0 [}] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_NestedTransitions_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_NestedTransitions_VSCode.semantic.txt new file mode 100644 index 00000000000..252722935ab --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_NestedTransitions_VSCode.semantic.txt @@ -0,0 +1,23 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 5 keyword 0 [using] +0 6 6 namespace 0 [System] +1 0 1 razorTransition 0 [@] +0 1 9 razorDirective 0 [functions] +0 10 1 razorTransition 0 [{] +1 4 6 delegate 0 [Action] +0 6 1 punctuation 0 [<] +0 1 6 keyword 0 [object] +0 6 1 punctuation 0 [>] +0 2 3 field 0 [abc] +0 4 1 operator 0 [=] +0 2 1 razorTransition 0 [@] +0 1 1 markupTagDelimiter 0 [<] +0 1 4 markupElement 0 [span] +0 4 1 markupTagDelimiter 0 [>] +0 1 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 4 markupElement 0 [span] +0 4 1 markupTagDelimiter 0 [>] +0 1 1 punctuation 0 [;] +1 0 1 razorTransition 0 [}] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_NonComponentsDoNotShowInRazorAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_NonComponentsDoNotShowInRazorAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..c2daf132722 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_NonComponentsDoNotShowInRazorAsync_VSCode.semantic.txt @@ -0,0 +1,15 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] +1 0 1 markupTagDelimiter 0 [<] +0 1 5 markupElement 0 [test1] +0 6 8 markupAttribute 0 [bool-val] +0 8 1 markupOperator 0 [=] +0 1 1 markupAttributeQuote 0 ['] +0 1 4 markupAttributeValue 0 [true] +0 4 1 markupAttributeQuote 0 ['] +0 1 1 markupTagDelimiter 0 [>] +0 1 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 5 markupElement 0 [test1] +0 5 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_UsingDirective_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_UsingDirective_VSCode.semantic.txt new file mode 100644 index 00000000000..5ed81254634 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_Razor_UsingDirective_VSCode.semantic.txt @@ -0,0 +1,6 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 5 keyword 0 [using] +0 6 6 namespace 0 [System] +0 6 1 operator 0 [.] +0 1 9 namespace 0 [Threading] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_TagHelpersNotAvailableInRazorAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_TagHelpersNotAvailableInRazorAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..e44e2be5376 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_TagHelpersNotAvailableInRazorAsync_VSCode.semantic.txt @@ -0,0 +1,20 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] +1 0 1 markupTagDelimiter 0 [<] +0 1 5 markupElement 0 [test1] +0 6 8 markupAttribute 0 [bool-val] +0 8 1 markupOperator 0 [=] +0 1 1 markupAttributeQuote 0 ['] +0 1 4 markupAttributeValue 0 [true] +0 4 1 markupAttributeQuote 0 ['] +0 2 5 markupAttribute 0 [class] +0 5 1 markupOperator 0 [=] +0 1 1 markupAttributeQuote 0 ['] +0 1 12 markupAttributeValue 0 [display:none] +0 12 1 markupAttributeQuote 0 ['] +0 1 1 markupTagDelimiter 0 [>] +0 1 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 5 markupElement 0 [test1] +0 5 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_WithAttributeAsync_VSCode.semantic.txt b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_WithAttributeAsync_VSCode.semantic.txt new file mode 100644 index 00000000000..d906869b03a --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.LanguageServer.Test/Semantic/TestFiles/GetSemanticTokens_WithAttributeAsync_VSCode.semantic.txt @@ -0,0 +1,15 @@ +//line,characterPos,length,tokenType,modifier,text +0 0 1 razorTransition 0 [@] +0 1 12 razorDirective 0 [addTagHelper] +1 0 1 markupTagDelimiter 0 [<] +0 1 5 razorTagHelperElement 0 [test1] +0 6 8 razorTagHelperAttribute 0 [bool-val] +0 8 1 markupOperator 0 [=] +0 1 1 markupAttributeQuote 0 ['] +0 1 4 keyword 0 [true] +0 4 1 markupAttributeQuote 0 ['] +0 1 1 markupTagDelimiter 0 [>] +0 1 1 markupTagDelimiter 0 [<] +0 1 1 markupTagDelimiter 0 [/] +0 1 5 razorTagHelperElement 0 [test1] +0 5 1 markupTagDelimiter 0 [>] diff --git a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/TestRazorSemanticTokensLegendService.cs b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/TestRazorSemanticTokensLegendService.cs index 8688dee484c..2591bb0462f 100644 --- a/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/TestRazorSemanticTokensLegendService.cs +++ b/src/razor/src/Razor/test/Microsoft.AspNetCore.Razor.Test.Common.Tooling/LanguageServer/TestRazorSemanticTokensLegendService.cs @@ -7,5 +7,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer.Semantic; internal static class TestRazorSemanticTokensLegendService { - public static RazorSemanticTokensLegendService Instance = new(new TestClientCapabilitiesService(new VSInternalClientCapabilities() { SupportsVisualStudioExtensions = true })); + private static RazorSemanticTokensLegendService s_vsInstance = new(new TestClientCapabilitiesService(new VSInternalClientCapabilities() { SupportsVisualStudioExtensions = true })); + private static RazorSemanticTokensLegendService s_vsCodeInstance = new(new TestClientCapabilitiesService(new VSInternalClientCapabilities() { SupportsVisualStudioExtensions = false })); + + public static RazorSemanticTokensLegendService GetInstance(bool supportsVSExtensions) + => supportsVSExtensions + ? s_vsInstance + : s_vsCodeInstance; } diff --git a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostDocumentPullDiagnosticsTest.cs b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostDocumentPullDiagnosticsTest.cs index 8c9be19f30d..b88d4bbff77 100644 --- a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostDocumentPullDiagnosticsTest.cs +++ b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostDocumentPullDiagnosticsTest.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Razor; +using Microsoft.AspNetCore.Razor.LanguageServer.Test; using Microsoft.AspNetCore.Razor.Test.Common; using Microsoft.CodeAnalysis.Razor.Diagnostics; using Microsoft.CodeAnalysis.Razor.Telemetry; @@ -159,7 +160,8 @@ private async Task VerifyDiagnosticsAsync(TestCode input, VSInternalDiagnosticRe var requestInvoker = new TestHtmlRequestInvoker([(VSInternalMethods.DocumentPullDiagnosticName, htmlResponse)]); var clientSettingsManager = new ClientSettingsManager([]); - var endpoint = new CohostDocumentPullDiagnosticsEndpoint(RemoteServiceInvoker, requestInvoker, clientSettingsManager, NoOpTelemetryReporter.Instance, LoggerFactory); + var clientCapabilitiesService = new TestClientCapabilitiesService(new VSInternalClientCapabilities { SupportsVisualStudioExtensions = true }); + var endpoint = new CohostDocumentPullDiagnosticsEndpoint(RemoteServiceInvoker, requestInvoker, clientSettingsManager, clientCapabilitiesService, NoOpTelemetryReporter.Instance, LoggerFactory); var result = taskListRequest ? await endpoint.GetTestAccessor().HandleTaskListItemRequestAsync(document, ["TODO"], DisposalToken) diff --git a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostSemanticTokensRangeEndpointTest.cs b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostSemanticTokensRangeEndpointTest.cs index 731580a3bd4..dec04e3ba5f 100644 --- a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostSemanticTokensRangeEndpointTest.cs +++ b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostSemanticTokensRangeEndpointTest.cs @@ -22,11 +22,12 @@ public class CohostSemanticTokensRangeEndpointTest(ITestOutputHelper testOutputH { [Theory] [CombinatorialData] - public async Task Razor(bool colorBackground, bool precise) + public async Task Razor(bool colorBackground, bool precise, bool supportsVSExtensions) { var input = """ @page "/" @using System + @using System.Diagnostics
This is some HTML
@@ -42,6 +43,11 @@ @using System @code { + [DebuggerDisplay("{GetDebuggerDisplay,nq}")] + public class MyClass + { + } + // I am also good, thanks for asking /* @@ -57,12 +63,12 @@ public void M() } """; - await VerifySemanticTokensAsync(input, colorBackground, precise); + await VerifySemanticTokensAsync(input, colorBackground, precise, supportsVSExtensions); } [Theory] [CombinatorialData] - public async Task Legacy(bool colorBackground, bool precise) + public async Task Legacy(bool colorBackground, bool precise, bool supportsVSExtensions) { var input = """ @page "/" @@ -85,12 +91,12 @@ @section MySection { } """; - await VerifySemanticTokensAsync(input, colorBackground, precise, fileKind: RazorFileKind.Legacy); + await VerifySemanticTokensAsync(input, colorBackground, precise, supportsVSExtensions, fileKind: RazorFileKind.Legacy); } [Theory] [CombinatorialData] - public async Task Legacy_Compatibility(bool colorBackground, bool precise) + public async Task Legacy_Compatibility(bool colorBackground, bool precise, bool supportsVSExtensions) { // Same test as above, but with only the things that work in FUSE and non-FUSE, to prevent regressions @@ -110,23 +116,33 @@ public void M() } """; - await VerifySemanticTokensAsync(input, colorBackground, precise, fileKind: RazorFileKind.Legacy); + await VerifySemanticTokensAsync(input, colorBackground, precise, supportsVSExtensions, fileKind: RazorFileKind.Legacy); } private async Task VerifySemanticTokensAsync( string input, bool colorBackground, bool precise, + bool supportsVSExtensions, RazorFileKind? fileKind = null, [CallerMemberName] string? testName = null) { var document = CreateProjectAndRazorDocument(input, fileKind); var sourceText = await document.GetTextAsync(DisposalToken); - var legend = TestRazorSemanticTokensLegendService.Instance; + var legend = TestRazorSemanticTokensLegendService.GetInstance(supportsVSExtensions); // We need to manually initialize the OOP service so we can get semantic token info later - UpdateClientLSPInitializationOptions(options => options with { TokenTypes = legend.TokenTypes.All, TokenModifiers = legend.TokenModifiers.All }); + UpdateClientLSPInitializationOptions(options => + { + options.ClientCapabilities.SupportsVisualStudioExtensions = supportsVSExtensions; + + return options with + { + TokenTypes = legend.TokenTypes.All, + TokenModifiers = legend.TokenModifiers.All, + }; + }); // Update the client initialization options to control the precise ranges option UpdateClientInitializationOptions(c => c with { UsePreciseSemanticTokenRanges = precise }); @@ -140,7 +156,12 @@ private async Task VerifySemanticTokensAsync( var result = await endpoint.GetTestAccessor().HandleRequestAsync(document, span, DisposalToken); - var actualFileContents = GetTestOutput(sourceText, result?.Data); + var actualFileContents = GetTestOutput(sourceText, result?.Data, legend); + + if (!supportsVSExtensions) + { + testName += "_VSCode"; + } if (colorBackground) { @@ -175,7 +196,7 @@ private static void WriteBaselineFile(string fileContents, string baselineFileNa File.WriteAllText(baselineFileFullPath, fileContents); } - private static string GetTestOutput(SourceText sourceText, int[]? data) + private static string GetTestOutput(SourceText sourceText, int[]? data, RazorSemanticTokensLegendService legend) { if (data == null) { @@ -184,7 +205,7 @@ private static string GetTestOutput(SourceText sourceText, int[]? data) using var _ = StringBuilderPool.GetPooledObject(out var builder); builder.AppendLine("Line Δ, Char Δ, Length, Type, Modifier(s), Text"); - var tokenTypes = TestRazorSemanticTokensLegendService.Instance.TokenTypes.All; + var tokenTypes = legend.TokenTypes.All; var prevLength = 0; var lineIndex = 0; var lineOffset = 0; @@ -206,7 +227,7 @@ private static string GetTestOutput(SourceText sourceText, int[]? data) lineOffset += charDelta; var type = tokenTypes[data[i + 3]]; - var modifier = GetTokenModifierString(data[i + 4]); + var modifier = GetTokenModifierString(data[i + 4], legend); var text = sourceText.GetSubTextString(new TextSpan(sourceText.Lines[lineIndex].Start + lineOffset, length)); builder.AppendLine($"{lineDelta} {charDelta} {length} {type} {modifier} [{text}]"); @@ -216,9 +237,9 @@ private static string GetTestOutput(SourceText sourceText, int[]? data) return builder.ToString(); } - private static string GetTokenModifierString(int tokenModifiers) + private static string GetTokenModifierString(int tokenModifiers, RazorSemanticTokensLegendService legend) { - var modifiers = TestRazorSemanticTokensLegendService.Instance.TokenModifiers.All; + var modifiers = legend.TokenModifiers.All; var modifiersBuilder = ArrayBuilder.GetInstance(); for (var i = 0; i < modifiers.Length; i++) diff --git a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/FormattingTestBase.cs b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/FormattingTestBase.cs index ec7076811e5..75b0a6d30dd 100644 --- a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/FormattingTestBase.cs +++ b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/FormattingTestBase.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.Razor.Formatting; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Remote; +using Microsoft.CodeAnalysis.Razor.Workspaces.Settings; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Razor.Settings; using Roslyn.Test.Utilities; diff --git a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs index 61950ef06c5..263d24c5678 100644 --- a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs +++ b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; using Microsoft.CodeAnalysis.Razor.Telemetry; using Microsoft.CodeAnalysis.Razor.Workspaces.Protocol.SemanticTokens; +using Microsoft.CodeAnalysis.Razor.Workspaces.Settings; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; using Microsoft.VisualStudio.Razor.Settings; diff --git a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Settings/ClientSettingsManagerTest.cs b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Settings/ClientSettingsManagerTest.cs index 6900265ebe0..2b09ec9cebc 100644 --- a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Settings/ClientSettingsManagerTest.cs +++ b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Settings/ClientSettingsManagerTest.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Razor.Test.Common.VisualStudio; using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Settings; +using Microsoft.CodeAnalysis.Razor.Workspaces.Settings; using Xunit; using Xunit.Abstractions; diff --git a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Legacy_Compatibility_VSCode.txt b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Legacy_Compatibility_VSCode.txt new file mode 100644 index 00000000000..89dc328b353 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Legacy_Compatibility_VSCode.txt @@ -0,0 +1,42 @@ +Line Δ, Char Δ, Length, Type, Modifier(s), Text +0 0 1 razorTransition [] [@] +0 1 4 razorDirective [] [page] +0 5 3 string [] ["/"] +1 0 1 razorTransition [] [@] +0 1 5 keyword [] [using] +0 6 6 namespace [] [System] +2 0 1 markupTagDelimiter [] [<] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +0 18 1 markupTagDelimiter [] [<] +0 1 1 markupTagDelimiter [] [/] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +2 0 1 markupTagDelimiter [] [<] +0 1 9 razorTagHelperElement [] [component] +0 10 4 razorTagHelperAttribute [] [type] +0 4 1 markupOperator [] [=] +0 1 1 markupAttributeQuote [] ["] +0 1 6 keyword [] [typeof] +0 6 1 punctuation [] [(] +0 1 9 property [] [Component] +0 9 1 punctuation [] [)] +0 1 1 markupAttributeQuote [] ["] +0 2 11 razorTagHelperAttribute [] [render-mode] +0 11 1 markupOperator [] [=] +0 1 1 markupAttributeQuote [] ["] +0 1 17 enumMember [] [ServerPrerendered] +0 17 1 markupAttributeQuote [] ["] +0 2 1 markupTagDelimiter [] [/] +0 1 1 markupTagDelimiter [] [>] +2 0 1 razorTransition [] [@] +0 1 9 razorDirective [] [functions] +1 0 1 razorTransition [] [{] +1 4 6 keyword [] [public] +0 7 4 keyword [] [void] +0 5 1 method [] [M] +0 1 1 punctuation [] [(] +0 1 1 punctuation [] [)] +1 4 1 punctuation [] [{] +1 4 1 punctuation [] [}] +1 0 1 razorTransition [] [}] diff --git a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Legacy_Compatibility_VSCode_with_background.txt b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Legacy_Compatibility_VSCode_with_background.txt new file mode 100644 index 00000000000..0fd272f0e85 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Legacy_Compatibility_VSCode_with_background.txt @@ -0,0 +1,48 @@ +Line Δ, Char Δ, Length, Type, Modifier(s), Text +0 0 1 razorTransition [] [@] +0 1 4 razorDirective [] [page] +0 5 3 string [razorCode] ["/"] +1 0 1 razorTransition [] [@] +0 1 5 keyword [razorCode] [using] +0 5 1 markupTextLiteral [razorCode] [ ] +0 1 6 namespace [razorCode] [System] +2 0 1 markupTagDelimiter [] [<] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +0 18 1 markupTagDelimiter [] [<] +0 1 1 markupTagDelimiter [] [/] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +2 0 1 markupTagDelimiter [] [<] +0 1 9 razorTagHelperElement [] [component] +0 10 4 razorTagHelperAttribute [] [type] +0 4 1 markupOperator [] [=] +0 1 1 markupAttributeQuote [] ["] +0 1 6 keyword [razorCode] [typeof] +0 6 1 punctuation [razorCode] [(] +0 1 9 property [razorCode] [Component] +0 9 1 punctuation [razorCode] [)] +0 1 1 markupAttributeQuote [] ["] +0 2 11 razorTagHelperAttribute [] [render-mode] +0 11 1 markupOperator [] [=] +0 1 1 markupAttributeQuote [] ["] +0 1 17 enumMember [razorCode] [ServerPrerendered] +0 17 1 markupAttributeQuote [] ["] +0 2 1 markupTagDelimiter [] [/] +0 1 1 markupTagDelimiter [] [>] +2 0 1 razorTransition [] [@] +0 1 9 razorDirective [] [functions] +1 0 1 razorTransition [] [{] +1 0 4 markupTextLiteral [razorCode] [ ] +0 4 6 keyword [razorCode] [public] +0 6 1 markupTextLiteral [razorCode] [ ] +0 1 4 keyword [razorCode] [void] +0 4 1 markupTextLiteral [razorCode] [ ] +0 1 1 method [razorCode] [M] +0 1 1 punctuation [razorCode] [(] +0 1 1 punctuation [razorCode] [)] +1 0 4 markupTextLiteral [razorCode] [ ] +0 4 1 punctuation [razorCode] [{] +1 0 4 markupTextLiteral [razorCode] [ ] +0 4 1 punctuation [razorCode] [}] +1 0 1 razorTransition [] [}] diff --git a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Legacy_VSCode.txt b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Legacy_VSCode.txt new file mode 100644 index 00000000000..f4c8cfb41c9 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Legacy_VSCode.txt @@ -0,0 +1,55 @@ +Line Δ, Char Δ, Length, Type, Modifier(s), Text +0 0 1 razorTransition [] [@] +0 1 4 razorDirective [] [page] +0 5 3 string [] ["/"] +1 0 1 razorTransition [] [@] +0 1 5 razorDirective [] [model] +1 0 1 razorTransition [] [@] +0 1 5 keyword [] [using] +0 6 6 namespace [] [System] +2 0 1 markupTagDelimiter [] [<] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +0 18 1 markupTagDelimiter [] [<] +0 1 1 markupTagDelimiter [] [/] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +2 0 1 markupTagDelimiter [] [<] +0 1 9 razorTagHelperElement [] [component] +0 10 4 razorTagHelperAttribute [] [type] +0 4 1 markupOperator [] [=] +0 1 1 markupAttributeQuote [] ["] +0 1 6 keyword [] [typeof] +0 6 1 punctuation [] [(] +0 1 9 property [] [Component] +0 9 1 punctuation [] [)] +0 1 1 markupAttributeQuote [] ["] +0 2 11 razorTagHelperAttribute [] [render-mode] +0 11 1 markupOperator [] [=] +0 1 1 markupAttributeQuote [] ["] +0 1 17 enumMember [] [ServerPrerendered] +0 17 1 markupAttributeQuote [] ["] +0 2 1 markupTagDelimiter [] [/] +0 1 1 markupTagDelimiter [] [>] +2 0 1 razorTransition [] [@] +0 1 9 razorDirective [] [functions] +1 0 1 razorTransition [] [{] +1 4 6 keyword [] [public] +0 7 4 keyword [] [void] +0 5 1 method [] [M] +0 1 1 punctuation [] [(] +0 1 1 punctuation [] [)] +1 4 1 punctuation [] [{] +1 4 1 punctuation [] [}] +1 0 1 razorTransition [] [}] +2 0 1 razorTransition [] [@] +0 1 7 razorDirective [] [section] +0 18 1 razorTransition [] [{] +1 4 1 markupTagDelimiter [] [<] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +0 16 1 markupTagDelimiter [] [<] +0 1 1 markupTagDelimiter [] [/] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +1 0 1 razorTransition [] [}] diff --git a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Legacy_VSCode_with_background.txt b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Legacy_VSCode_with_background.txt new file mode 100644 index 00000000000..ad0cb479cfc --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Legacy_VSCode_with_background.txt @@ -0,0 +1,61 @@ +Line Δ, Char Δ, Length, Type, Modifier(s), Text +0 0 1 razorTransition [] [@] +0 1 4 razorDirective [] [page] +0 5 3 string [razorCode] ["/"] +1 0 1 razorTransition [] [@] +0 1 5 razorDirective [] [model] +1 0 1 razorTransition [] [@] +0 1 5 keyword [razorCode] [using] +0 5 1 markupTextLiteral [razorCode] [ ] +0 1 6 namespace [razorCode] [System] +2 0 1 markupTagDelimiter [] [<] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +0 18 1 markupTagDelimiter [] [<] +0 1 1 markupTagDelimiter [] [/] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +2 0 1 markupTagDelimiter [] [<] +0 1 9 razorTagHelperElement [] [component] +0 10 4 razorTagHelperAttribute [] [type] +0 4 1 markupOperator [] [=] +0 1 1 markupAttributeQuote [] ["] +0 1 6 keyword [razorCode] [typeof] +0 6 1 punctuation [razorCode] [(] +0 1 9 property [razorCode] [Component] +0 9 1 punctuation [razorCode] [)] +0 1 1 markupAttributeQuote [] ["] +0 2 11 razorTagHelperAttribute [] [render-mode] +0 11 1 markupOperator [] [=] +0 1 1 markupAttributeQuote [] ["] +0 1 17 enumMember [razorCode] [ServerPrerendered] +0 17 1 markupAttributeQuote [] ["] +0 2 1 markupTagDelimiter [] [/] +0 1 1 markupTagDelimiter [] [>] +2 0 1 razorTransition [] [@] +0 1 9 razorDirective [] [functions] +1 0 1 razorTransition [] [{] +1 0 4 markupTextLiteral [razorCode] [ ] +0 4 6 keyword [razorCode] [public] +0 6 1 markupTextLiteral [razorCode] [ ] +0 1 4 keyword [razorCode] [void] +0 4 1 markupTextLiteral [razorCode] [ ] +0 1 1 method [razorCode] [M] +0 1 1 punctuation [razorCode] [(] +0 1 1 punctuation [razorCode] [)] +1 0 4 markupTextLiteral [razorCode] [ ] +0 4 1 punctuation [razorCode] [{] +1 0 4 markupTextLiteral [razorCode] [ ] +0 4 1 punctuation [razorCode] [}] +1 0 1 razorTransition [] [}] +2 0 1 razorTransition [] [@] +0 1 7 razorDirective [] [section] +0 18 1 razorTransition [] [{] +1 4 1 markupTagDelimiter [] [<] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +0 16 1 markupTagDelimiter [] [<] +0 1 1 markupTagDelimiter [] [/] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +1 0 1 razorTransition [] [}] diff --git a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Razor.txt b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Razor.txt index 14db5713c1e..be8a321c993 100644 --- a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Razor.txt +++ b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Razor.txt @@ -5,6 +5,11 @@ Line Δ, Char Δ, Length, Type, Modifier(s), Text 1 0 1 razorTransition [] [@] 0 1 5 keyword [] [using] 0 6 6 namespace name [] [System] +1 0 1 razorTransition [] [@] +0 1 5 keyword [] [using] +0 6 6 namespace name [] [System] +0 6 1 operator [] [.] +0 1 11 namespace name [] [Diagnostics] 2 0 1 markupTagDelimiter [] [<] 0 1 3 markupElement [] [div] 0 3 1 markupTagDelimiter [] [>] @@ -41,7 +46,18 @@ Line Δ, Char Δ, Length, Type, Modifier(s), Text 2 0 1 razorTransition [] [@] 0 1 4 razorDirective [] [code] 1 0 1 razorTransition [] [{] -1 4 36 comment [] [// I am also good, thanks for asking] +1 4 1 punctuation [] [[] +0 1 15 class name [] [DebuggerDisplay] +0 15 1 punctuation [] [(] +0 1 25 string [] ["{GetDebuggerDisplay,nq}"] +0 25 1 punctuation [] [)] +0 1 1 punctuation [] []] +1 4 6 keyword [] [public] +0 7 5 keyword [] [class] +0 6 7 class name [] [MyClass] +1 4 1 punctuation [] [{] +1 4 1 punctuation [] [}] +2 4 36 comment [] [// I am also good, thanks for asking] 2 4 2 comment [] [/*] 1 0 19 comment [] [ No problem.] 1 0 6 comment [] [ */] diff --git a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Razor_VSCode.txt b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Razor_VSCode.txt new file mode 100644 index 00000000000..2e4d936bf29 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Razor_VSCode.txt @@ -0,0 +1,87 @@ +Line Δ, Char Δ, Length, Type, Modifier(s), Text +0 0 1 razorTransition [] [@] +0 1 4 razorDirective [] [page] +0 5 3 string [] ["/"] +1 0 1 razorTransition [] [@] +0 1 5 keyword [] [using] +0 6 6 namespace [] [System] +1 0 1 razorTransition [] [@] +0 1 5 keyword [] [using] +0 6 6 namespace [] [System] +0 6 1 operator [] [.] +0 1 11 namespace [] [Diagnostics] +2 0 1 markupTagDelimiter [] [<] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +0 18 1 markupTagDelimiter [] [<] +0 1 1 markupTagDelimiter [] [/] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +2 0 1 markupTagDelimiter [] [<] +0 1 9 razorComponentElement [] [InputText] +0 10 5 razorComponentAttribute [] [Value] +0 5 1 markupOperator [] [=] +0 1 1 markupAttributeQuote [] ["] +0 1 9 markupAttributeValue [] [someValue] +0 9 1 markupAttributeQuote [] ["] +0 2 1 markupTagDelimiter [] [/] +0 1 1 markupTagDelimiter [] [>] +2 0 1 razorCommentTransition [] [@] +0 1 1 razorCommentStar [] [*] +0 1 13 razorComment [] [ hello there ] +0 13 1 razorCommentStar [] [*] +0 1 1 razorCommentTransition [] [@] +1 0 4 markupCommentPunctuation [] [] +2 0 1 razorTransition [] [@] +0 1 2 controlKeyword [] [if] +0 3 1 punctuation [] [(] +0 1 4 keyword [] [true] +0 4 1 punctuation [] [)] +1 0 1 punctuation [] [{] +1 4 6 razorDirective [] [] +0 11 7 razorDirective [] [] +1 0 1 punctuation [] [}] +2 0 1 razorTransition [] [@] +0 1 4 razorDirective [] [code] +1 0 1 razorTransition [] [{] +1 4 1 punctuation [] [[] +0 1 15 class [] [DebuggerDisplay] +0 15 1 punctuation [] [(] +0 1 25 string [] ["{GetDebuggerDisplay,nq}"] +0 25 1 punctuation [] [)] +0 1 1 punctuation [] []] +1 4 6 keyword [] [public] +0 7 5 keyword [] [class] +0 6 7 class [] [MyClass] +1 4 1 punctuation [] [{] +1 4 1 punctuation [] [}] +2 4 36 comment [] [// I am also good, thanks for asking] +2 4 2 comment [] [/*] +1 0 19 comment [] [ No problem.] +1 0 6 comment [] [ */] +2 4 7 keyword [] [private] +0 8 6 keyword [] [string] +0 7 9 field [] [someValue] +0 9 1 punctuation [] [;] +2 4 6 keyword [] [public] +0 7 4 keyword [] [void] +0 5 1 method [] [M] +0 1 1 punctuation [] [(] +0 1 1 punctuation [] [)] +1 4 1 punctuation [] [{] +1 8 14 delegate [] [RenderFragment] +0 15 1 variable [] [x] +0 2 1 operator [] [=] +0 2 1 razorTransition [] [@] +0 1 1 markupTagDelimiter [] [<] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +0 39 1 markupTagDelimiter [] [<] +0 1 1 markupTagDelimiter [] [/] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +0 1 1 punctuation [] [;] +1 4 1 punctuation [] [}] +1 0 1 razorTransition [] [}] diff --git a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Razor_VSCode_with_background.txt b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Razor_VSCode_with_background.txt new file mode 100644 index 00000000000..8932585ec35 --- /dev/null +++ b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Razor_VSCode_with_background.txt @@ -0,0 +1,109 @@ +Line Δ, Char Δ, Length, Type, Modifier(s), Text +0 0 1 razorTransition [] [@] +0 1 4 razorDirective [] [page] +0 5 3 string [razorCode] ["/"] +1 0 1 razorTransition [] [@] +0 1 5 keyword [razorCode] [using] +0 5 1 markupTextLiteral [razorCode] [ ] +0 1 6 namespace [razorCode] [System] +1 0 1 razorTransition [] [@] +0 1 5 keyword [razorCode] [using] +0 5 1 markupTextLiteral [razorCode] [ ] +0 1 6 namespace [razorCode] [System] +0 6 1 operator [razorCode] [.] +0 1 11 namespace [razorCode] [Diagnostics] +2 0 1 markupTagDelimiter [] [<] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +0 18 1 markupTagDelimiter [] [<] +0 1 1 markupTagDelimiter [] [/] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +2 0 1 markupTagDelimiter [] [<] +0 1 9 razorComponentElement [] [InputText] +0 10 5 razorComponentAttribute [] [Value] +0 5 1 markupOperator [] [=] +0 1 1 markupAttributeQuote [] ["] +0 1 9 markupAttributeValue [] [someValue] +0 9 1 markupAttributeQuote [] ["] +0 2 1 markupTagDelimiter [] [/] +0 1 1 markupTagDelimiter [] [>] +2 0 1 razorCommentTransition [] [@] +0 1 1 razorCommentStar [] [*] +0 1 13 razorComment [] [ hello there ] +0 13 1 razorCommentStar [] [*] +0 1 1 razorCommentTransition [] [@] +1 0 4 markupCommentPunctuation [] [] +2 0 1 razorTransition [razorCode] [@] +0 1 2 controlKeyword [razorCode] [if] +0 2 1 markupTextLiteral [razorCode] [ ] +0 1 1 punctuation [razorCode] [(] +0 1 4 keyword [razorCode] [true] +0 4 1 punctuation [razorCode] [)] +1 0 1 punctuation [razorCode] [{] +1 4 6 razorDirective [] [] +0 11 7 razorDirective [] [] +1 0 1 punctuation [razorCode] [}] +2 0 1 razorTransition [] [@] +0 1 4 razorDirective [] [code] +1 0 1 razorTransition [] [{] +1 0 4 markupTextLiteral [razorCode] [ ] +0 4 1 punctuation [razorCode] [[] +0 1 15 class [razorCode] [DebuggerDisplay] +0 15 1 punctuation [razorCode] [(] +0 1 25 string [razorCode] ["{GetDebuggerDisplay,nq}"] +0 25 1 punctuation [razorCode] [)] +0 1 1 punctuation [razorCode] []] +1 0 4 markupTextLiteral [razorCode] [ ] +0 4 6 keyword [razorCode] [public] +0 6 1 markupTextLiteral [razorCode] [ ] +0 1 5 keyword [razorCode] [class] +0 5 1 markupTextLiteral [razorCode] [ ] +0 1 7 class [razorCode] [MyClass] +1 0 4 markupTextLiteral [razorCode] [ ] +0 4 1 punctuation [razorCode] [{] +1 0 4 markupTextLiteral [razorCode] [ ] +0 4 1 punctuation [razorCode] [}] +2 0 4 markupTextLiteral [razorCode] [ ] +0 4 36 comment [razorCode] [// I am also good, thanks for asking] +2 0 4 markupTextLiteral [razorCode] [ ] +0 4 2 comment [razorCode] [/*] +1 0 19 comment [razorCode] [ No problem.] +1 0 6 comment [razorCode] [ */] +2 0 4 markupTextLiteral [razorCode] [ ] +0 4 7 keyword [razorCode] [private] +0 7 1 markupTextLiteral [razorCode] [ ] +0 1 6 keyword [razorCode] [string] +0 6 1 markupTextLiteral [razorCode] [ ] +0 1 9 field [razorCode] [someValue] +0 9 1 punctuation [razorCode] [;] +2 0 4 markupTextLiteral [razorCode] [ ] +0 4 6 keyword [razorCode] [public] +0 6 1 markupTextLiteral [razorCode] [ ] +0 1 4 keyword [razorCode] [void] +0 4 1 markupTextLiteral [razorCode] [ ] +0 1 1 method [razorCode] [M] +0 1 1 punctuation [razorCode] [(] +0 1 1 punctuation [razorCode] [)] +1 0 4 markupTextLiteral [razorCode] [ ] +0 4 1 punctuation [razorCode] [{] +1 0 8 markupTextLiteral [razorCode] [ ] +0 8 14 delegate [razorCode] [RenderFragment] +0 14 1 markupTextLiteral [razorCode] [ ] +0 1 1 variable [razorCode] [x] +0 1 1 markupTextLiteral [razorCode] [ ] +0 1 1 operator [razorCode] [=] +0 2 1 razorTransition [razorCode] [@] +0 1 1 markupTagDelimiter [] [<] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +0 39 1 markupTagDelimiter [] [<] +0 1 1 markupTagDelimiter [] [/] +0 1 3 markupElement [] [div] +0 3 1 markupTagDelimiter [] [>] +0 1 1 punctuation [razorCode] [;] +1 0 4 markupTextLiteral [razorCode] [ ] +0 4 1 punctuation [razorCode] [}] +1 0 1 razorTransition [] [}] diff --git a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Razor_with_background.txt b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Razor_with_background.txt index 59dc6ecd00f..03cbf3337c3 100644 --- a/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Razor_with_background.txt +++ b/src/razor/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/TestFiles/SemanticTokens/Razor_with_background.txt @@ -6,6 +6,12 @@ Line Δ, Char Δ, Length, Type, Modifier(s), Text 0 1 5 keyword [razorCode] [using] 0 5 1 markupTextLiteral [razorCode] [ ] 0 1 6 namespace name [razorCode] [System] +1 0 1 razorTransition [] [@] +0 1 5 keyword [razorCode] [using] +0 5 1 markupTextLiteral [razorCode] [ ] +0 1 6 namespace name [razorCode] [System] +0 6 1 operator [razorCode] [.] +0 1 11 namespace name [razorCode] [Diagnostics] 2 0 1 markupTagDelimiter [] [<] 0 1 3 markupElement [] [div] 0 3 1 markupTagDelimiter [] [>] @@ -44,6 +50,23 @@ Line Δ, Char Δ, Length, Type, Modifier(s), Text 0 1 4 razorDirective [] [code] 1 0 1 razorTransition [] [{] 1 0 4 markupTextLiteral [razorCode] [ ] +0 4 1 punctuation [razorCode] [[] +0 1 15 class name [razorCode] [DebuggerDisplay] +0 15 1 punctuation [razorCode] [(] +0 1 25 string [razorCode] ["{GetDebuggerDisplay,nq}"] +0 25 1 punctuation [razorCode] [)] +0 1 1 punctuation [razorCode] []] +1 0 4 markupTextLiteral [razorCode] [ ] +0 4 6 keyword [razorCode] [public] +0 6 1 markupTextLiteral [razorCode] [ ] +0 1 5 keyword [razorCode] [class] +0 5 1 markupTextLiteral [razorCode] [ ] +0 1 7 class name [razorCode] [MyClass] +1 0 4 markupTextLiteral [razorCode] [ ] +0 4 1 punctuation [razorCode] [{] +1 0 4 markupTextLiteral [razorCode] [ ] +0 4 1 punctuation [razorCode] [}] +2 0 4 markupTextLiteral [razorCode] [ ] 0 4 36 comment [razorCode] [// I am also good, thanks for asking] 2 0 4 markupTextLiteral [razorCode] [ ] 0 4 2 comment [razorCode] [/*] diff --git a/src/razor/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/RazorDocumentManagerTest.cs b/src/razor/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/RazorDocumentManagerTest.cs index 8ceb8795195..be9ee3b56e4 100644 --- a/src/razor/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/RazorDocumentManagerTest.cs +++ b/src/razor/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/RazorDocumentManagerTest.cs @@ -6,8 +6,8 @@ using Microsoft.AspNetCore.Razor.Test.Common.ProjectSystem; using Microsoft.AspNetCore.Razor.Test.Common.VisualStudio; using Microsoft.CodeAnalysis.Razor.ProjectEngineHost; +using Microsoft.CodeAnalysis.Razor.Workspaces.Settings; using Microsoft.VisualStudio.LegacyEditor.Razor.Settings; -using Microsoft.VisualStudio.Razor.Settings; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Moq; diff --git a/src/razor/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Settings/WorkspaceEditorSettingsTest.cs b/src/razor/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Settings/WorkspaceEditorSettingsTest.cs index e059fa29193..4bfb269ac06 100644 --- a/src/razor/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Settings/WorkspaceEditorSettingsTest.cs +++ b/src/razor/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/Settings/WorkspaceEditorSettingsTest.cs @@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Razor.Test.Common.Accessors; using Microsoft.AspNetCore.Razor.Test.Common.VisualStudio; using Microsoft.CodeAnalysis.Razor.Settings; -using Microsoft.VisualStudio.Razor.Settings; +using Microsoft.CodeAnalysis.Razor.Workspaces.Settings; using Moq; using Xunit; using Xunit.Abstractions; @@ -54,7 +54,7 @@ public void ClientSettingsChangedTriggersChangedEvent() settingsManagerMock.Raise( x => x.ClientSettingsChanged += null, - new ClientSettingsChangedEventArgs(ClientSettings.Default)); + EventArgs.Empty); // Assert Assert.True(called); @@ -73,11 +73,11 @@ public void ClientSettingsChangedIsOnlyHookedOnceForMultipleListeners() var editorSettings = new WorkspaceEditorSettings(settingsManagerMock.Object); var accessor = new TestAccessor(editorSettings); - static void Listener1(object caller, ClientSettingsChangedEventArgs args) + static void Listener1(object caller, EventArgs args) { } - static void Listener2(object caller, ClientSettingsChangedEventArgs args) + static void Listener2(object caller, EventArgs args) { } @@ -89,7 +89,7 @@ static void Listener2(object caller, ClientSettingsChangedEventArgs args) Assert.Equal(2, accessor._listenerCount); settingsManagerMock.VerifyAdd( - x => x.ClientSettingsChanged += It.IsAny>(), + x => x.ClientSettingsChanged += It.IsAny>(), Times.Once()); // Act 2 @@ -100,7 +100,7 @@ static void Listener2(object caller, ClientSettingsChangedEventArgs args) Assert.Equal(0, accessor._listenerCount); settingsManagerMock.VerifyRemove( - x => x.ClientSettingsChanged -= It.IsAny>(), + x => x.ClientSettingsChanged -= It.IsAny>(), Times.Once()); } diff --git a/src/razor/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/VisualStudioDocumentTrackerTest.cs b/src/razor/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/VisualStudioDocumentTrackerTest.cs index fe53909815e..8b9756e5718 100644 --- a/src/razor/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/VisualStudioDocumentTrackerTest.cs +++ b/src/razor/src/Razor/test/Microsoft.VisualStudio.LegacyEditor.Razor.Test/VisualStudioDocumentTrackerTest.cs @@ -10,10 +10,10 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor; using Microsoft.CodeAnalysis.Razor.ProjectSystem; +using Microsoft.CodeAnalysis.Razor.Workspaces.Settings; using Microsoft.VisualStudio.LegacyEditor.Razor.Settings; using Microsoft.VisualStudio.Razor; using Microsoft.VisualStudio.Razor.Documents; -using Microsoft.VisualStudio.Razor.Settings; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Moq; diff --git a/src/razor/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess.cs b/src/razor/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess.cs index 86500619e86..cbb2f734117 100644 --- a/src/razor/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess.cs +++ b/src/razor/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/EditorInProcess.cs @@ -8,11 +8,11 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.Settings; +using Microsoft.CodeAnalysis.Razor.Workspaces.Settings; using Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion; using Microsoft.VisualStudio.OLE.Interop; using Microsoft.VisualStudio.Razor.IntegrationTests.Extensions; using Microsoft.VisualStudio.Razor.IntegrationTests.InProcess; -using Microsoft.VisualStudio.Razor.Settings; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; diff --git a/src/razor/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/OutputInProcess.cs b/src/razor/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/OutputInProcess.cs index 358e850579e..4d248c4d8fc 100644 --- a/src/razor/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/OutputInProcess.cs +++ b/src/razor/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/InProcess/OutputInProcess.cs @@ -5,9 +5,9 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.Logging; +using Microsoft.CodeAnalysis.Razor.Workspaces.Settings; using Microsoft.VisualStudio.Razor.IntegrationTests.Extensions; using Microsoft.VisualStudio.Razor.IntegrationTests.Logging; -using Microsoft.VisualStudio.Razor.Settings; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.TextManager.Interop; diff --git a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/EnumerableExtensionsTests.cs b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/EnumerableExtensionsTests.cs index a549039b2b9..358bfe00267 100644 --- a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/EnumerableExtensionsTests.cs +++ b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/EnumerableExtensionsTests.cs @@ -140,4 +140,24 @@ IEnumerator IEnumerable.GetEnumerator() public static CustomReadOnlyCollection Create(ReadOnlySpan span) => new(span); } + + [Fact] + public void SelectAsArray() + { + IEnumerable data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + ImmutableArray expected = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]; + + var actual = data.SelectAsArray(static x => x * 2); + Assert.Equal(expected, actual); + } + + [Fact] + public void SelectAsArray_Index() + { + IEnumerable data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + ImmutableArray expected = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]; + + var actual = data.SelectAsArray(static (x, index) => x + index); + Assert.Equal(expected, actual); + } } diff --git a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/EnumerableOrderingTests.cs b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/EnumerableOrderingTests.cs index ad5a60cb182..8adcf8ad8e5 100644 --- a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/EnumerableOrderingTests.cs +++ b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/EnumerableOrderingTests.cs @@ -17,7 +17,7 @@ public class EnumerableOrderingTests : EnumerableOrderingTestBase public void OrderAsArray(IEnumerable data, ImmutableArray expected) { var sorted = data.OrderAsArray(); - Assert.Equal(expected, sorted); + AssertEqual(expected, sorted); } [Theory] @@ -25,7 +25,7 @@ public void OrderAsArray(IEnumerable data, ImmutableArray expected) public void OrderAsArray_OddBeforeEven(IEnumerable data, ImmutableArray expected) { var sorted = data.OrderAsArray(OddBeforeEven); - Assert.Equal(expected, sorted); + AssertEqual(expected, sorted); } [Theory] @@ -33,7 +33,7 @@ public void OrderAsArray_OddBeforeEven(IEnumerable data, ImmutableArray data, ImmutableArray expected) { var sorted = data.OrderDescendingAsArray(); - Assert.Equal(expected, sorted); + AssertEqual(expected, sorted); } [Theory] @@ -41,7 +41,7 @@ public void OrderDescendingAsArray(IEnumerable data, ImmutableArray ex public void OrderDescendingAsArray_OddBeforeEven(IEnumerable data, ImmutableArray expected) { var sorted = data.OrderDescendingAsArray(OddBeforeEven); - Assert.Equal(expected, sorted); + AssertEqual(expected, sorted); } [Theory] @@ -76,6 +76,70 @@ public void OrderByDescendingAsArray_OddBeforeEven(IEnumerable> AssertEqual(expected, sorted); } + [Theory] + [MemberData(nameof(SelectAndOrderTestData))] + public void SelectAndOrderAsArray(IEnumerable data, ImmutableArray expected, Func selector) + { + var sorted = data.SelectAndOrderAsArray(selector); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderTestData_OddBeforeEven))] + public void SelectAndOrderAsArray_OddBeforeEven(IEnumerable data, ImmutableArray expected, Func selector) + { + var sorted = data.SelectAndOrderAsArray(selector, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderDescendingTestData))] + public void SelectAndOrderDescendingAsArray(IEnumerable data, ImmutableArray expected, Func selector) + { + var sorted = data.SelectAndOrderDescendingAsArray(selector); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderDescendingTestData_OddBeforeEven))] + public void SelectAndOrderDescendingAsArray_OddBeforeEven(IEnumerable data, ImmutableArray expected, Func selector) + { + var sorted = data.SelectAndOrderDescendingAsArray(selector, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByTestData))] + public void SelectAndOrderByAsArray(IEnumerable> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var sorted = data.SelectAndOrderByAsArray(selector, static x => x.Value); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByTestData_OddBeforeEven))] + public void SelectAndOrderByAsArray_OddBeforeEven(IEnumerable> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var sorted = data.SelectAndOrderByAsArray(selector, static x => x.Value, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByDescendingTestData))] + public void SelectAndOrderByDescendingAsArray(IEnumerable> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var sorted = data.SelectAndOrderByDescendingAsArray(selector, static x => x.Value); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByDescendingTestData_OddBeforeEven))] + public void SelectAndOrderByDescendingAsArray_OddBeforeEven(IEnumerable> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var sorted = data.SelectAndOrderByDescendingAsArray(selector, static x => x.Value, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + #if NET // Enumerable.Order(...) and Enumerable.OrderDescending(...) were introduced in .NET 7 [Fact] diff --git a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/ImmutableArrayExtensionsTests.cs b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/ImmutableArrayExtensionsTests.cs index c8a436095c4..5671c3635db 100644 --- a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/ImmutableArrayExtensionsTests.cs +++ b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/ImmutableArrayExtensionsTests.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Collections.Immutable; using Xunit; @@ -36,4 +37,72 @@ public void GetMostRecentUniqueItems() }, s => Assert.Equal("WoRlD", s)); } + + [Fact] + public void SelectAsArray() + { + ImmutableArray data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + ImmutableArray expected = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]; + + var actual = data.SelectAsArray(static x => x * 2); + Assert.Equal(expected, actual); + } + + [Fact] + public void SelectAsArray_ReadOnlyList() + { + ImmutableArray data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + ImmutableArray expected = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]; + + var list = (IReadOnlyList)data; + + var actual = list.SelectAsArray(static x => x * 2); + Assert.Equal(expected, actual); + } + + [Fact] + public void SelectAsArray_Enumerable() + { + ImmutableArray data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + ImmutableArray expected = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]; + + var enumerable = (IEnumerable)data; + + var actual = enumerable.SelectAsArray(static x => x * 2); + Assert.Equal(expected, actual); + } + + [Fact] + public void SelectAsArray_Index() + { + ImmutableArray data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + ImmutableArray expected = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]; + + var actual = data.SelectAsArray(static (x, index) => x + index); + Assert.Equal(expected, actual); + } + + [Fact] + public void SelectAsArray_Index_ReadOnlyList() + { + ImmutableArray data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + ImmutableArray expected = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]; + + var list = (IReadOnlyList)data; + + var actual = list.SelectAsArray(static (x, index) => x + index); + Assert.Equal(expected, actual); + } + + [Fact] + public void SelectAsArray_Index_Enumerable() + { + ImmutableArray data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + ImmutableArray expected = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]; + + var enumerable = (IEnumerable)data; + + var actual = enumerable.SelectAsArray(static (x, index) => x + index); + Assert.Equal(expected, actual); + } } diff --git a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/ImmutableArrayOrderingTests.cs b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/ImmutableArrayOrderingTests.cs index 64229f4d61a..83e05dd780a 100644 --- a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/ImmutableArrayOrderingTests.cs +++ b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/ImmutableArrayOrderingTests.cs @@ -221,6 +221,214 @@ public void OrderByDescendingAsArray_Enumerable_OddBeforeEven(ImmutableArray data, ImmutableArray expected, Func selector) + { + var sorted = data.SelectAndOrderAsArray(selector); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderTestData_OddBeforeEven))] + public void SelectAndOrderAsArray_OddBeforeEven(ImmutableArray data, ImmutableArray expected, Func selector) + { + var sorted = data.SelectAndOrderAsArray(selector, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderDescendingTestData))] + public void SelectAndOrderDescendingAsArray(ImmutableArray data, ImmutableArray expected, Func selector) + { + var sorted = data.SelectAndOrderDescendingAsArray(selector); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderDescendingTestData_OddBeforeEven))] + public void SelectAndOrderDescendingAsArray_OddBeforeEven(ImmutableArray data, ImmutableArray expected, Func selector) + { + var sorted = data.SelectAndOrderDescendingAsArray(selector, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByTestData))] + public void SelectAndOrderByAsArray(ImmutableArray> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var sorted = data.SelectAndOrderByAsArray(selector, static x => x.Value); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByTestData_OddBeforeEven))] + public void SelectAndOrderByAsArray_OddBeforeEven(ImmutableArray> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var sorted = data.SelectAndOrderByAsArray(selector, static x => x.Value, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByDescendingTestData))] + public void SelectAndOrderByDescendingAsArray(ImmutableArray> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var sorted = data.SelectAndOrderByDescendingAsArray(selector, static x => x.Value); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByDescendingTestData_OddBeforeEven))] + public void SelectAndOrderByDescendingAsArray_OddBeforeEven(ImmutableArray> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var sorted = data.SelectAndOrderByDescendingAsArray(selector, static x => x.Value, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderTestData))] + public void SelectAndOrderAsArray_ReadOnlyList(ImmutableArray data, ImmutableArray expected, Func selector) + { + var readOnlyList = (IReadOnlyList)data; + var sorted = readOnlyList.SelectAndOrderAsArray(selector); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderTestData_OddBeforeEven))] + public void SelectAndOrderAsArray_ReadOnlyList_OddBeforeEven(ImmutableArray data, ImmutableArray expected, Func selector) + { + var readOnlyList = (IReadOnlyList)data; + var sorted = readOnlyList.SelectAndOrderAsArray(selector, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderDescendingTestData))] + public void SelectAndOrderDescendingAsArray_ReadOnlyList(ImmutableArray data, ImmutableArray expected, Func selector) + { + var readOnlyList = (IReadOnlyList)data; + var sorted = readOnlyList.SelectAndOrderDescendingAsArray(selector); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderDescendingTestData_OddBeforeEven))] + public void SelectAndOrderDescendingAsArray_ReadOnlyList_OddBeforeEven(ImmutableArray data, ImmutableArray expected, Func selector) + { + var readOnlyList = (IReadOnlyList)data; + var sorted = readOnlyList.SelectAndOrderDescendingAsArray(selector, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByTestData))] + public void SelectAndOrderByAsArray_ReadOnlyList(ImmutableArray> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var readOnlyList = (IReadOnlyList>)data; + var sorted = readOnlyList.SelectAndOrderByAsArray(selector, static x => x.Value); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByTestData_OddBeforeEven))] + public void SelectAndOrderByAsArray_ReadOnlyList_OddBeforeEven(ImmutableArray> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var readOnlyList = (IReadOnlyList>)data; + var sorted = readOnlyList.SelectAndOrderByAsArray(selector, static x => x.Value, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByDescendingTestData))] + public void SelectAndOrderByDescendingAsArray_ReadOnlyList(ImmutableArray> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var readOnlyList = (IReadOnlyList>)data; + var sorted = readOnlyList.SelectAndOrderByDescendingAsArray(selector, static x => x.Value); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByDescendingTestData_OddBeforeEven))] + public void SelectAndOrderByDescendingAsArray_ReadOnlyList_OddBeforeEven(ImmutableArray> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var readOnlyList = (IReadOnlyList>)data; + var sorted = readOnlyList.SelectAndOrderByDescendingAsArray(selector, static x => x.Value, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderTestData))] + public void SelectAndOrderAsArray_Enumerable(ImmutableArray data, ImmutableArray expected, Func selector) + { + var enumerable = (IEnumerable)data; + var sorted = enumerable.SelectAndOrderAsArray(selector); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderTestData_OddBeforeEven))] + public void SelectAndOrderAsArray_Enumerable_OddBeforeEven(ImmutableArray data, ImmutableArray expected, Func selector) + { + var enumerable = (IEnumerable)data; + var sorted = enumerable.SelectAndOrderAsArray(selector, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderDescendingTestData))] + public void SelectAndOrderDescendingAsArray_Enumerable(ImmutableArray data, ImmutableArray expected, Func selector) + { + var enumerable = (IEnumerable)data; + var sorted = enumerable.SelectAndOrderDescendingAsArray(selector); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderDescendingTestData_OddBeforeEven))] + public void SelectAndOrderDescendingAsArray_Enumerable_OddBeforeEven(ImmutableArray data, ImmutableArray expected, Func selector) + { + var enumerable = (IEnumerable)data; + var sorted = enumerable.SelectAndOrderDescendingAsArray(selector, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByTestData))] + public void SelectAndOrderByAsArray_Enumerable(ImmutableArray> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var enumerable = (IEnumerable>)data; + var sorted = enumerable.SelectAndOrderByAsArray(selector, static x => x.Value); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByTestData_OddBeforeEven))] + public void SelectAndOrderByAsArray_Enumerable_OddBeforeEven(ImmutableArray> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var enumerable = (IEnumerable>)data; + var sorted = enumerable.SelectAndOrderByAsArray(selector, static x => x.Value, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByDescendingTestData))] + public void SelectAndOrderByDescendingAsArray_Enumerable(ImmutableArray> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var enumerable = (IEnumerable>)data; + var sorted = enumerable.SelectAndOrderByDescendingAsArray(selector, static x => x.Value); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByDescendingTestData_OddBeforeEven))] + public void SelectAndOrderByDescendingAsArray_Enumerable_OddBeforeEven(ImmutableArray> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var enumerable = (IEnumerable>)data; + var sorted = enumerable.SelectAndOrderByDescendingAsArray(selector, static x => x.Value, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + [Theory] [MemberData(nameof(OrderTestData))] public void ToImmutableOrdered(ImmutableArray data, ImmutableArray expected) diff --git a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/ReadOnlyListExtensionsTests.cs b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/ReadOnlyListExtensionsTests.cs index bcf37734efd..9fa836ff08a 100644 --- a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/ReadOnlyListExtensionsTests.cs +++ b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/ReadOnlyListExtensionsTests.cs @@ -278,4 +278,48 @@ IEnumerator IEnumerable.GetEnumerator() public static CustomReadOnlyList Create(ReadOnlySpan span) => new(span); } + + [Fact] + public void SelectAsArray() + { + IReadOnlyList data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + ImmutableArray expected = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]; + + var actual = data.SelectAsArray(static x => x * 2); + Assert.Equal(expected, actual); + } + + [Fact] + public void SelectAsArray_Enumerable() + { + IReadOnlyList data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + ImmutableArray expected = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]; + + var enumerable = (IEnumerable)data; + + var actual = enumerable.SelectAsArray(static x => x * 2); + Assert.Equal(expected, actual); + } + + [Fact] + public void SelectAsArray_Index() + { + IReadOnlyList data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + ImmutableArray expected = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]; + + var actual = data.SelectAsArray(static (x, index) => x + index); + Assert.Equal(expected, actual); + } + + [Fact] + public void SelectAsArray_Index_Enumerable() + { + IReadOnlyList data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + ImmutableArray expected = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]; + + var enumerable = (IEnumerable)data; + + var actual = enumerable.SelectAsArray(static (x, index) => x + index); + Assert.Equal(expected, actual); + } } diff --git a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/ReadOnlyListOrderingTests.cs b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/ReadOnlyListOrderingTests.cs index 959c10ca298..4fb7a60129d 100644 --- a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/ReadOnlyListOrderingTests.cs +++ b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/ReadOnlyListOrderingTests.cs @@ -148,6 +148,142 @@ public void OrderByDescendingAsArray_Enumerable_OddBeforeEven(IReadOnlyList data, ImmutableArray expected, Func selector) + { + var sorted = data.SelectAndOrderAsArray(selector); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderTestData_OddBeforeEven))] + public void SelectAndOrderAsArray_OddBeforeEven(IReadOnlyList data, ImmutableArray expected, Func selector) + { + var sorted = data.SelectAndOrderAsArray(selector, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderDescendingTestData))] + public void SelectAndOrderDescendingAsArray(IReadOnlyList data, ImmutableArray expected, Func selector) + { + var sorted = data.SelectAndOrderDescendingAsArray(selector); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderDescendingTestData_OddBeforeEven))] + public void SelectAndOrderDescendingAsArray_OddBeforeEven(IReadOnlyList data, ImmutableArray expected, Func selector) + { + var sorted = data.SelectAndOrderDescendingAsArray(selector, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByTestData))] + public void SelectAndOrderByAsArray(IReadOnlyList> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var sorted = data.SelectAndOrderByAsArray(selector, static x => x.Value); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByTestData_OddBeforeEven))] + public void SelectAndOrderByAsArray_OddBeforeEven(IReadOnlyList> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var sorted = data.SelectAndOrderByAsArray(selector, static x => x.Value, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByDescendingTestData))] + public void SelectAndOrderByDescendingAsArray(IReadOnlyList> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var sorted = data.SelectAndOrderByDescendingAsArray(selector, static x => x.Value); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByDescendingTestData_OddBeforeEven))] + public void SelectAndOrderByDescendingAsArray_OddBeforeEven(IReadOnlyList> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var sorted = data.SelectAndOrderByDescendingAsArray(selector, static x => x.Value, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderTestData))] + public void SelectAndOrderAsArray_Enumerable(IReadOnlyList data, ImmutableArray expected, Func selector) + { + var enumerable = (IEnumerable)data; + var sorted = enumerable.SelectAndOrderAsArray(selector); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderTestData_OddBeforeEven))] + public void SelectAndOrderAsArray_Enumerable_OddBeforeEven(IReadOnlyList data, ImmutableArray expected, Func selector) + { + var enumerable = (IEnumerable)data; + var sorted = enumerable.SelectAndOrderAsArray(selector, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderDescendingTestData))] + public void SelectAndOrderDescendingAsArray_Enumerable(IReadOnlyList data, ImmutableArray expected, Func selector) + { + var enumerable = (IEnumerable)data; + var sorted = enumerable.SelectAndOrderDescendingAsArray(selector); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderDescendingTestData_OddBeforeEven))] + public void SelectAndOrderDescendingAsArray_Enumerable_OddBeforeEven(IReadOnlyList data, ImmutableArray expected, Func selector) + { + var enumerable = (IEnumerable)data; + var sorted = enumerable.SelectAndOrderDescendingAsArray(selector, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByTestData))] + public void SelectAndOrderByAsArray_Enumerable(IReadOnlyList> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var enumerable = (IEnumerable>)data; + var sorted = enumerable.SelectAndOrderByAsArray(selector, static x => x.Value); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByTestData_OddBeforeEven))] + public void SelectAndOrderByAsArray_Enumerable_OddBeforeEven(IReadOnlyList> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var enumerable = (IEnumerable>)data; + var sorted = enumerable.SelectAndOrderByAsArray(selector, static x => x.Value, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByDescendingTestData))] + public void SelectAndOrderByDescendingAsArray_Enumerable(IReadOnlyList> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var enumerable = (IEnumerable>)data; + var sorted = enumerable.SelectAndOrderByDescendingAsArray(selector, static x => x.Value); + AssertEqual(expected, sorted); + } + + [Theory] + [MemberData(nameof(SelectAndOrderByDescendingTestData_OddBeforeEven))] + public void SelectAndOrderByDescendingAsArray_Enumerable_OddBeforeEven(IReadOnlyList> data, ImmutableArray> expected, Func, ValueHolder> selector) + { + var enumerable = (IEnumerable>)data; + var sorted = enumerable.SelectAndOrderByDescendingAsArray(selector, static x => x.Value, OddBeforeEvenString); + AssertEqual(expected, sorted); + } + #if NET // Enumerable.Order(...) and Enumerable.OrderDescending(...) were introduced in .NET 7 [Fact] diff --git a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/TestData/OrderingTestBase.cs b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/TestData/OrderingTestBase.cs index 584bf59fbf8..3c88317b552 100644 --- a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/TestData/OrderingTestBase.cs +++ b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared.Test/TestData/OrderingTestBase.cs @@ -22,20 +22,59 @@ public abstract class OrderingTestBase>> s_orderByDescendingTestData = []; private static readonly TheoryData>> s_orderByDescendingTestData_OddBeforeEven = []; - protected static void AddCase(TOrderCollection collection) + private static readonly TheoryData, Func> s_selectAndOrderTestData = []; + private static readonly TheoryData, Func> s_selectAndOrderTestData_OddBeforeEven = []; + private static readonly TheoryData, Func> s_selectAndOrderDescendingTestData = []; + private static readonly TheoryData, Func> s_selectAndOrderDescendingTestData_OddBeforeEven = []; + private static readonly TheoryData>, Func, ValueHolder>> s_selectAndOrderByTestData = []; + private static readonly TheoryData>, Func, ValueHolder>> s_selectAndOrderByTestData_OddBeforeEven = []; + private static readonly TheoryData>, Func, ValueHolder>> s_selectAndOrderByDescendingTestData = []; + private static readonly TheoryData>, Func, ValueHolder>> s_selectAndOrderByDescendingTestData_OddBeforeEven = []; + + private static readonly ImmutableArray s_expectedOrder = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + private static readonly ImmutableArray s_expectedOrder_OddBeforeEven = [1, 3, 5, 7, 9, 2, 4, 6, 8, 10]; + private static readonly ImmutableArray s_expectedOrderDescending = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; + private static readonly ImmutableArray s_expectedOrderDescending_OddBeforeEven = [10, 8, 6, 4, 2, 9, 7, 5, 3, 1]; + + private static readonly ImmutableArray> s_expectedOrderBy = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + private static readonly ImmutableArray> s_expectedOrderBy_OddBeforeEven = [1, 3, 5, 7, 9, 2, 4, 6, 8, 10]; + private static readonly ImmutableArray> s_expectedOrderByDescending = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; + private static readonly ImmutableArray> s_expectedOrderByDescending_OddBeforeEven = [10, 8, 6, 4, 2, 9, 7, 5, 3, 1]; + + private static readonly ImmutableArray s_expectedSelectAndOrder = ["1", "10", "2", "3", "4", "5", "6", "7", "8", "9"]; + private static readonly ImmutableArray s_expectedSelectAndOrder_OddBeforeEven = ["1", "3", "5", "7", "9", "10", "2", "4", "6", "8"]; + private static readonly ImmutableArray s_expectedSelectAndOrderDescending = ["9", "8", "7", "6", "5", "4", "3", "2", "10", "1"]; + private static readonly ImmutableArray s_expectedSelectAndOrderDescending_OddBeforeEven = ["8", "6", "4", "2", "10", "9", "7", "5", "3", "1"]; + + private static readonly ImmutableArray> s_expectedSelectAndOrderBy = ["1", "10", "2", "3", "4", "5", "6", "7", "8", "9"]; + private static readonly ImmutableArray> s_expectedSelectAndOrderBy_OddBeforeEven = ["1", "3", "5", "7", "9", "10", "2", "4", "6", "8"]; + private static readonly ImmutableArray> s_expectedSelectAndOrderByDescending = ["9", "8", "7", "6", "5", "4", "3", "2", "10", "1"]; + private static readonly ImmutableArray> s_expectedSelectAndOrderByDescending_OddBeforeEven = ["8", "6", "4", "2", "10", "9", "7", "5", "3", "1"]; + + private static void AddCase(TOrderCollection collection) { - s_orderTestData.Add(collection, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - s_orderTestData_OddBeforeEven.Add(collection, [1, 3, 5, 7, 9, 2, 4, 6, 8, 10]); - s_orderDescendingTestData.Add(collection, [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]); - s_orderDescendingTestData_OddBeforeEven.Add(collection, [10, 8, 6, 4, 2, 9, 7, 5, 3, 1]); + s_orderTestData.Add(collection, s_expectedOrder); + s_orderTestData_OddBeforeEven.Add(collection, s_expectedOrder_OddBeforeEven); + s_orderDescendingTestData.Add(collection, s_expectedOrderDescending); + s_orderDescendingTestData_OddBeforeEven.Add(collection, s_expectedOrderDescending_OddBeforeEven); + + s_selectAndOrderTestData.Add(collection, s_expectedSelectAndOrder, static x => x.ToString()); + s_selectAndOrderTestData_OddBeforeEven.Add(collection, s_expectedSelectAndOrder_OddBeforeEven, static x => x.ToString()); + s_selectAndOrderDescendingTestData.Add(collection, s_expectedSelectAndOrderDescending, static x => x.ToString()); + s_selectAndOrderDescendingTestData_OddBeforeEven.Add(collection, s_expectedSelectAndOrderDescending_OddBeforeEven, static x => x.ToString()); } - protected static void AddCase(TOrderByCollection collection) + private static void AddCase(TOrderByCollection collection) { - s_orderByTestData.Add(collection, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - s_orderByTestData_OddBeforeEven.Add(collection, [1, 3, 5, 7, 9, 2, 4, 6, 8, 10]); - s_orderByDescendingTestData.Add(collection, [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]); - s_orderByDescendingTestData_OddBeforeEven.Add(collection, [10, 8, 6, 4, 2, 9, 7, 5, 3, 1]); + s_orderByTestData.Add(collection, s_expectedOrderBy); + s_orderByTestData_OddBeforeEven.Add(collection, s_expectedOrderBy_OddBeforeEven); + s_orderByDescendingTestData.Add(collection, s_expectedOrderByDescending); + s_orderByDescendingTestData_OddBeforeEven.Add(collection, s_expectedOrderByDescending_OddBeforeEven); + + s_selectAndOrderByTestData.Add(collection, s_expectedSelectAndOrderBy, static x => x.Value.ToString()); + s_selectAndOrderByTestData_OddBeforeEven.Add(collection, s_expectedSelectAndOrderBy_OddBeforeEven, static x => x.Value.ToString()); + s_selectAndOrderByDescendingTestData.Add(collection, s_expectedSelectAndOrderByDescending, static x => x.Value.ToString()); + s_selectAndOrderByDescendingTestData_OddBeforeEven.Add(collection, s_expectedSelectAndOrderByDescending_OddBeforeEven, static x => x.Value.ToString()); } static OrderingTestBase() @@ -63,6 +102,14 @@ protected static Comparison OddBeforeEven _ => x.CompareTo(y) }; + protected static Comparison OddBeforeEvenString + => (x, y) => (int.Parse(x) % 2 != 0, int.Parse(y) % 2 != 0) switch + { + (true, false) => -1, + (false, true) => 1, + _ => x.CompareTo(y) + }; + public static TheoryData> OrderTestData => s_orderTestData; public static TheoryData> OrderTestData_OddBeforeEven => s_orderTestData_OddBeforeEven; public static TheoryData> OrderDescendingTestData => s_orderDescendingTestData; @@ -72,6 +119,15 @@ protected static Comparison OddBeforeEven public static TheoryData>> OrderByDescendingTestData => s_orderByDescendingTestData; public static TheoryData>> OrderByDescendingTestData_OddBeforeEven => s_orderByDescendingTestData_OddBeforeEven; + public static TheoryData, Func> SelectAndOrderTestData => s_selectAndOrderTestData; + public static TheoryData, Func> SelectAndOrderTestData_OddBeforeEven => s_selectAndOrderTestData_OddBeforeEven; + public static TheoryData, Func> SelectAndOrderDescendingTestData => s_selectAndOrderDescendingTestData; + public static TheoryData, Func> SelectAndOrderDescendingTestData_OddBeforeEven => s_selectAndOrderDescendingTestData_OddBeforeEven; + public static TheoryData>, Func, ValueHolder>> SelectAndOrderByTestData => s_selectAndOrderByTestData; + public static TheoryData>, Func, ValueHolder>> SelectAndOrderByTestData_OddBeforeEven => s_selectAndOrderByTestData_OddBeforeEven; + public static TheoryData>, Func, ValueHolder>> SelectAndOrderByDescendingTestData => s_selectAndOrderByDescendingTestData; + public static TheoryData>, Func, ValueHolder>> SelectAndOrderByDescendingTestData_OddBeforeEven => s_selectAndOrderByDescendingTestData_OddBeforeEven; + protected void AssertEqual(ImmutableArray result, ImmutableArray expected) { Assert.Equal(result, expected); diff --git a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/EnumerableExtensions.cs b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/EnumerableExtensions.cs index 0017b1e40a0..5d7a6552bae 100644 --- a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/EnumerableExtensions.cs +++ b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/EnumerableExtensions.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See License.txt in the project root for license information. using System.Collections.Immutable; +using System.Diagnostics; using System.Runtime.InteropServices; using Microsoft.AspNetCore.Razor; using Microsoft.AspNetCore.Razor.PooledObjects; @@ -11,31 +12,141 @@ namespace System.Collections.Generic; internal static class EnumerableExtensions { + /// + /// Projects each element of an into a new form. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// A sequence of values to invoke a transform function on. + /// A transform function to apply to each element. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of . + /// public static ImmutableArray SelectAsArray(this IEnumerable source, Func selector) { + // If the source is an ImmutableArray boxed as an IEnumerable, it's better to unbox it here and + // call the SelectAsArray extension method that takes an ImmutableArray. Otherwise, it'll go + // through the IReadOnlyList path. + if (source is ImmutableArray array) + { + return ImmutableArrayExtensions.SelectAsArray(array, selector); + } + + // If the source is an IReadOnlyList, we should call the SelectAsArray extension method that + // takes an IReadOnlyList. This ensures that we don't foreach over it and incur the cost of allocating + // or boxing an enumerator. + if (source is IReadOnlyList list) + { + return ReadOnlyListExtensions.SelectAsArray(list, selector); + } + + // PERF: If we can get the count of the sequence, we can allocate the array up front. + if (source.TryGetCount(out var count)) + { + if (count == 0) + { + return []; + } + + var result = new TResult[count]; + + var index = 0; + foreach (var item in source) + { + result[index++] = selector(item); + } + + Debug.Assert(result.Length == count); + + return ImmutableCollectionsMarshal.AsImmutableArray(result); + } + + // Fall back to a PooledArrayBuilder if we can't get the count up front. + // If the enumerable has 4 or fewer items, this will still allocate a single array and fill it. + // However, if it has more than 4 items, it will acquire an ImmutableArray.Builder from the default pool. + using var results = new PooledArrayBuilder(); + + foreach (var item in source) + { + results.Add(selector(item)); + } + + // If the PooledArrayBuilder acquired an ImmutableArray.Builder, using DrainToImmutable() + // avoid's allocating a new array and copying the results into it if the builder's capacity *happens* + // to be the same as the number of items. This is uncommon, but still useful. + return results.DrainToImmutable(); + } + + /// + /// Projects each element of an into a new form by incorporating the element's index. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// A sequence of values to invoke a transform function on. + /// + /// A transform function to apply to each source element; the second parameter of + /// the function represents the index of the source element. + /// + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of . + /// + public static ImmutableArray SelectAsArray(this IEnumerable source, Func selector) + { + // If the source is an ImmutableArray boxed as an IEnumerable, it's better to unbox it here and + // call the SelectAsArray extension method that takes an ImmutableArray. Otherwise, it'll go + // through the IReadOnlyList path. if (source is ImmutableArray array) { return ImmutableArrayExtensions.SelectAsArray(array, selector); } + // If the source is an IReadOnlyList, we should call the SelectAsArray extension method that + // takes an IReadOnlyList. This ensures that we don't foreach over it and incur the cost of allocating + // or boxing an enumerator. if (source is IReadOnlyList list) { - return list.SelectAsArray(selector); + return ReadOnlyListExtensions.SelectAsArray(list, selector); } - return BuildResult(source, selector); + var index = 0; - static ImmutableArray BuildResult(IEnumerable items, Func selector) + // PERF: If we can get the count of the sequence, we can allocate the array up front. + if (source.TryGetCount(out var count)) { - using var results = new PooledArrayBuilder(); + if (count == 0) + { + return []; + } + + var result = new TResult[count]; - foreach (var item in items) + foreach (var item in source) { - results.Add(selector(item)); + result[index] = selector(item, index); + index++; } - return results.DrainToImmutable(); + Debug.Assert(result.Length == count); + + return ImmutableCollectionsMarshal.AsImmutableArray(result); } + + // Fall back to a PooledArrayBuilder if we can't get the count up front. + // If the enumerable has 4 or fewer items, this will still allocate a single array and fill it. + // However, if it has more than 4 items, it will acquire an ImmutableArray.Builder from the default pool. + using var results = new PooledArrayBuilder(); + + foreach (var item in source) + { + results.Add(selector(item, index++)); + } + + // If the PooledArrayBuilder acquired an ImmutableArray.Builder, using DrainToImmutable() + // avoid's allocating a new array and copying the results into it if the builder's capacity *happens* + // to be the same as the number of items. This is uncommon, but still useful. + return results.DrainToImmutable(); } public static bool TryGetCount(this IEnumerable sequence, out int count) @@ -132,7 +243,7 @@ static void CopySequence(IEnumerable sequence, Span destination) /// Sorts the elements of an in ascending order. ///
/// The type of the elements in . - /// An to ordered. + /// An whose elements will be sorted. /// /// Returns a new whose elements are sorted in ascending order. /// @@ -156,7 +267,7 @@ public static ImmutableArray OrderAsArray(this IEnumerable sequence) /// Sorts the elements of an in ascending order. ///
/// The type of the elements in . - /// An to ordered. + /// An whose elements will be sorted. /// An to compare elements. /// /// Returns a new whose elements are sorted in ascending order. @@ -181,7 +292,7 @@ public static ImmutableArray OrderAsArray(this IEnumerable sequence, IC /// Sorts the elements of an in ascending order. ///
/// The type of the elements in . - /// An to ordered. + /// An whose elements will be sorted. /// An to compare elements. /// /// Returns a new whose elements are sorted in ascending order. @@ -206,7 +317,7 @@ public static ImmutableArray OrderAsArray(this IEnumerable sequence, Co /// Sorts the elements of an in descending order. ///
/// The type of the elements in . - /// An to ordered. + /// An whose elements will be sorted. /// /// Returns a new whose elements are sorted in descending order. /// @@ -230,7 +341,7 @@ public static ImmutableArray OrderDescendingAsArray(this IEnumerable se /// Sorts the elements of an in descending order. ///
/// The type of the elements in . - /// An to ordered. + /// An whose elements will be sorted. /// An to compare elements. /// /// Returns a new whose elements are sorted in descending order. @@ -255,7 +366,7 @@ public static ImmutableArray OrderDescendingAsArray(this IEnumerable se /// Sorts the elements of an in descending order. ///
/// The type of the elements in . - /// An to ordered. + /// An whose elements will be sorted. /// An to compare elements. /// /// Returns a new whose elements are sorted in descending order. @@ -281,7 +392,7 @@ public static ImmutableArray OrderDescendingAsArray(this IEnumerable se /// /// The type of the elements in . /// The type of key returned by . - /// An to ordered. + /// An whose elements will be sorted. /// A function to extract a key from an element. /// /// Returns a new whose elements are sorted in ascending order according to a key. @@ -308,7 +419,7 @@ public static ImmutableArray OrderByAsArray( /// /// The type of the elements in . /// The type of key returned by . - /// An to ordered. + /// An whose elements will be sorted. /// A function to extract a key from an element. /// An to compare keys. /// @@ -336,7 +447,7 @@ public static ImmutableArray OrderByAsArray( /// /// The type of the elements in . /// The type of key returned by . - /// An to ordered. + /// An whose elements will be sorted. /// A function to extract a key from an element. /// An to compare keys. /// @@ -364,7 +475,7 @@ public static ImmutableArray OrderByAsArray( /// /// The type of the elements in . /// The type of key returned by . - /// An to ordered. + /// An whose elements will be sorted. /// A function to extract a key from an element. /// /// Returns a new whose elements are sorted in descending order according to a key. @@ -391,7 +502,7 @@ public static ImmutableArray OrderByDescendingAsArray( /// /// The type of the elements in . /// The type of key returned by . - /// An to ordered. + /// An whose elements will be sorted. /// A function to extract a key from an element. /// An to compare keys. /// @@ -419,7 +530,7 @@ public static ImmutableArray OrderByDescendingAsArray( /// /// The type of the elements in . /// The type of key returned by . - /// An to ordered. + /// An whose elements will be sorted. /// A function to extract a key from an element. /// An to compare keys. /// @@ -496,4 +607,262 @@ static T[] BuildSlow(IEnumerable sequence) return builder.ToArray(); } } + + /// + /// Projects each element of an into a new form and sorts them in ascending order. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in ascending order. + /// + public static ImmutableArray SelectAndOrderAsArray(this IEnumerable sequence, Func selector) + { + var result = sequence.SelectAsArray(selector); + result.Unsafe().Order(); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in ascending order. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// An to compare elements. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in ascending order. + /// + public static ImmutableArray SelectAndOrderAsArray( + this IEnumerable sequence, Func selector, IComparer comparer) + { + var result = sequence.SelectAsArray(selector); + result.Unsafe().Order(comparer); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in ascending order. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// An to compare elements. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in ascending order. + /// + public static ImmutableArray SelectAndOrderAsArray( + this IEnumerable sequence, Func selector, Comparison comparison) + { + var result = sequence.SelectAsArray(selector); + result.Unsafe().Order(comparison); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in descending order. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in descending order. + /// + public static ImmutableArray SelectAndOrderDescendingAsArray(this IEnumerable sequence, Func selector) + { + var result = sequence.SelectAsArray(selector); + result.Unsafe().OrderDescending(); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in descending order. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// An to compare elements. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in descending order. + /// + public static ImmutableArray SelectAndOrderDescendingAsArray( + this IEnumerable sequence, Func selector, IComparer comparer) + { + var result = sequence.SelectAsArray(selector); + result.Unsafe().OrderDescending(comparer); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in descending order. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// An to compare elements. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in descending order. + /// + public static ImmutableArray SelectAndOrderDescendingAsArray( + this IEnumerable sequence, Func selector, Comparison comparison) + { + var result = sequence.SelectAsArray(selector); + result.Unsafe().OrderDescending(comparison); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in ascending order according to a key. + /// + /// The type of the elements in . + /// The type of key returned by . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A function to extract a key from an element. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in ascending order according to a key. + /// + public static ImmutableArray SelectAndOrderByAsArray( + this IEnumerable sequence, Func selector, Func keySelector) + { + var result = sequence.SelectAsArray(selector); + result.Unsafe().OrderBy(keySelector); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in ascending order according to a key. + /// + /// The type of the elements in . + /// The type of key returned by . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A function to extract a key from an element. + /// An to compare keys. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in ascending order according to a key. + /// + public static ImmutableArray SelectAndOrderByAsArray( + this IEnumerable sequence, Func selector, Func keySelector, IComparer comparer) + { + var result = sequence.SelectAsArray(selector); + result.Unsafe().OrderBy(keySelector, comparer); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in ascending order according to a key. + /// + /// The type of the elements in . + /// The type of key returned by . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A function to extract a key from an element. + /// An to compare keys. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in ascending order according to a key. + /// + public static ImmutableArray SelectAndOrderByAsArray( + this IEnumerable sequence, Func selector, Func keySelector, Comparison comparison) + { + var result = sequence.SelectAsArray(selector); + result.Unsafe().OrderBy(keySelector, comparison); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in descending order according to a key. + /// + /// The type of the elements in . + /// The type of key returned by . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A function to extract a key from an element. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in decending order according to a key. + /// + public static ImmutableArray SelectAndOrderByDescendingAsArray( + this IEnumerable sequence, Func selector, Func keySelector) + { + var result = sequence.SelectAsArray(selector); + result.Unsafe().OrderByDescending(keySelector); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in descending order according to a key. + /// + /// The type of the elements in . + /// The type of key returned by . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A function to extract a key from an element. + /// An to compare keys. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in decending order according to a key. + /// + public static ImmutableArray SelectAndOrderByDescendingAsArray( + this IEnumerable sequence, Func selector, Func keySelector, IComparer comparer) + { + var result = sequence.SelectAsArray(selector); + result.Unsafe().OrderByDescending(keySelector, comparer); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in descending order according to a key. + /// + /// The type of the elements in . + /// The type of key returned by . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A function to extract a key from an element. + /// An to compare keys. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in decending order according to a key. + /// + public static ImmutableArray SelectAndOrderByDescendingAsArray( + this IEnumerable sequence, Func selector, Func keySelector, Comparison comparison) + { + var result = sequence.SelectAsArray(selector); + result.Unsafe().OrderByDescending(keySelector, comparison); + + return result; + } } diff --git a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/ImmutableArrayExtensions.cs b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/ImmutableArrayExtensions.cs index 0bf6e151c1c..38482eddfc5 100644 --- a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/ImmutableArrayExtensions.cs +++ b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/ImmutableArrayExtensions.cs @@ -30,29 +30,66 @@ public static void SetCapacityIfLarger(this ImmutableArray.Builder builder } } - public static ImmutableArray SelectAsArray(this ImmutableArray source, Func selector) + /// + /// Projects each element of an into a new form. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An array of values to invoke a transform function on. + /// A transform function to apply to each element. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of . + /// + public static ImmutableArray SelectAsArray(this ImmutableArray array, Func selector) { - return source switch + var length = array.Length; + + if (length == 0) { - [] => [], - [var item] => [selector(item)], - [var item1, var item2] => [selector(item1), selector(item2)], - [var item1, var item2, var item3] => [selector(item1), selector(item2), selector(item3)], - [var item1, var item2, var item3, var item4] => [selector(item1), selector(item2), selector(item3), selector(item4)], - var items => BuildResult(items, selector) - }; - - static ImmutableArray BuildResult(ImmutableArray items, Func selector) + return []; + } + + var result = new TResult[length]; + + for (var i = 0; i < length; i++) { - using var results = new PooledArrayBuilder(capacity: items.Length); + result[i] = selector(array[i]); + } - foreach (var item in items) - { - results.Add(selector(item)); - } + return ImmutableCollectionsMarshal.AsImmutableArray(result); + } + + /// + /// Projects each element of an into a new form by incorporating the element's index. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An array of values to invoke a transform function on. + /// + /// A transform function to apply to each element; the second parameter of the function represents the index of the element. + /// + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of . + /// + public static ImmutableArray SelectAsArray(this ImmutableArray array, Func selector) + { + var length = array.Length; + + if (length == 0) + { + return []; + } + + var result = new TResult[length]; - return results.DrainToImmutable(); + for (var i = 0; i < length; i++) + { + result[i] = selector(array[i], i); } + + return ImmutableCollectionsMarshal.AsImmutableArray(result); } public static ImmutableArray SelectManyAsArray(this IReadOnlyCollection? source, Func> selector) @@ -227,7 +264,7 @@ public static int BinarySearchBy(this ImmutableArray array, TArg arg /// Sorts the elements of an in ascending order. /// /// The type of the elements in . - /// An array to ordered. + /// An array to be sorted. /// /// Returns a new whose elements are sorted in ascending order. /// @@ -241,7 +278,7 @@ public static ImmutableArray OrderAsArray(this ImmutableArray array) /// Sorts the elements of an in ascending order. /// /// The type of the elements in . - /// An array to ordered. + /// An array to be sorted. /// An to compare elements. /// /// Returns a new whose elements are sorted in ascending order. @@ -256,7 +293,7 @@ public static ImmutableArray OrderAsArray(this ImmutableArray array, IC /// Sorts the elements of an in ascending order. /// /// The type of the elements in . - /// An array to ordered. + /// An array to be sorted. /// A to compare elements. /// /// Returns a new whose elements are sorted in ascending order. @@ -271,7 +308,7 @@ public static ImmutableArray OrderAsArray(this ImmutableArray array, Co /// Sorts the elements of an in descending order. /// /// The type of the elements in . - /// An array to ordered. + /// An array to be sorted. /// /// Returns a new whose elements are sorted in descending order. /// @@ -285,7 +322,7 @@ public static ImmutableArray OrderDescendingAsArray(this ImmutableArray /// Sorts the elements of an in descending order. /// /// The type of the elements in . - /// An array to ordered. + /// An array to be sorted. /// An to compare elements. /// /// Returns a new whose elements are sorted in descending order. @@ -300,7 +337,7 @@ public static ImmutableArray OrderDescendingAsArray(this ImmutableArray /// Sorts the elements of an in descending order. /// /// The type of the elements in . - /// An array to ordered. + /// An array to be sorted. /// A to compare elements. /// /// Returns a new whose elements are sorted in descending order. @@ -316,7 +353,7 @@ public static ImmutableArray OrderDescendingAsArray(this ImmutableArray /// /// The type of the elements in . /// The type of key returned by . - /// An array to ordered. + /// An array to be sorted. /// A function to extract a key from an element. /// /// Returns a new whose elements are sorted in ascending order according to a key. @@ -333,7 +370,7 @@ public static ImmutableArray OrderByAsArray( /// /// The type of the elements in . /// The type of key returned by . - /// An array to ordered. + /// An array to be sorted. /// A function to extract a key from an element. /// An to compare keys. /// @@ -351,7 +388,7 @@ public static ImmutableArray OrderByAsArray( /// /// The type of the elements in . /// The type of key returned by . - /// An array to ordered. + /// An array to be sorted. /// A function to extract a key from an element. /// A to compare keys. /// @@ -369,7 +406,7 @@ public static ImmutableArray OrderByAsArray( /// /// The type of the elements in . /// The type of key returned by . - /// An array to ordered. + /// An array to be sorted. /// A function to extract a key from an element. /// /// Returns a new whose elements are sorted in descending order according to a key. @@ -386,7 +423,7 @@ public static ImmutableArray OrderByDescendingAsArray( /// /// The type of the elements in . /// The type of key returned by . - /// An array to ordered. + /// An array to be sorted. /// A function to extract a key from an element. /// An to compare keys. /// @@ -404,7 +441,7 @@ public static ImmutableArray OrderByDescendingAsArray( /// /// The type of the elements in . /// The type of key returned by . - /// An array to ordered. + /// An array to be sorted. /// A function to extract a key from an element. /// A to compare keys. /// @@ -978,4 +1015,262 @@ public static ImmutableArray DrainToImmutableOrderedByDescending + /// Projects each element of an into a new form and sorts them in ascending order. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An array of values to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in ascending order. + /// + public static ImmutableArray SelectAndOrderAsArray(this ImmutableArray array, Func selector) + { + var result = array.SelectAsArray(selector); + result.Unsafe().Order(); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in ascending order. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An array of values to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// An to compare projected elements. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in ascending order. + /// + public static ImmutableArray SelectAndOrderAsArray( + this ImmutableArray array, Func selector, IComparer comparer) + { + var result = array.SelectAsArray(selector); + result.Unsafe().Order(comparer); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in ascending order. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An array of values to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A to compare elements. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in ascending order. + /// + public static ImmutableArray SelectAndOrderAsArray( + this ImmutableArray array, Func selector, Comparison comparison) + { + var result = array.SelectAsArray(selector); + result.Unsafe().Order(comparison); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in descending order. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An array of values to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in descending order. + /// + public static ImmutableArray SelectAndOrderDescendingAsArray(this ImmutableArray array, Func selector) + { + var result = array.SelectAsArray(selector); + result.Unsafe().OrderDescending(); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in descending order. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An array of values to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// An to compare elements. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in descending order. + /// + public static ImmutableArray SelectAndOrderDescendingAsArray( + this ImmutableArray array, Func selector, IComparer comparer) + { + var result = array.SelectAsArray(selector); + result.Unsafe().OrderDescending(comparer); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in descending order. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An array of values to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A to compare elements. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in descending order. + /// + public static ImmutableArray SelectAndOrderDescendingAsArray( + this ImmutableArray array, Func selector, Comparison comparison) + { + var result = array.SelectAsArray(selector); + result.Unsafe().OrderDescending(comparison); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in ascending order according to a key. + /// + /// The type of the elements in . + /// The type of key returned by . + /// The type of the value returned by . + /// An array of values to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A function to extract a key from a projected element. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in ascending order according to a key. + /// + public static ImmutableArray SelectAndOrderByAsArray( + this ImmutableArray array, Func selector, Func keySelector) + { + var result = array.SelectAsArray(selector); + result.Unsafe().OrderBy(keySelector); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in ascending order according to a key. + /// + /// The type of the elements in . + /// The type of key returned by . + /// The type of the value returned by . + /// An array of values to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A function to extract a key from a projected element. + /// An to compare keys. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in ascending order according to a key. + /// + public static ImmutableArray SelectAndOrderByAsArray( + this ImmutableArray array, Func selector, Func keySelector, IComparer comparer) + { + var result = array.SelectAsArray(selector); + result.Unsafe().OrderBy(keySelector, comparer); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in ascending order according to a key. + /// + /// The type of the elements in . + /// The type of key returned by . + /// The type of the value returned by . + /// An array of values to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A function to extract a key from a projected element. + /// A to compare keys. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in ascending order according to a key. + /// + public static ImmutableArray SelectAndOrderByAsArray( + this ImmutableArray array, Func selector, Func keySelector, Comparison comparison) + { + var result = array.SelectAsArray(selector); + result.Unsafe().OrderBy(keySelector, comparison); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in descending order according to a key. + /// + /// The type of the elements in . + /// The type of key returned by . + /// The type of the value returned by . + /// An array of values to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A function to extract a key from a projected element. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in descending order according to a key. + /// + public static ImmutableArray SelectAndOrderByDescendingAsArray( + this ImmutableArray array, Func selector, Func keySelector) + { + var result = array.SelectAsArray(selector); + result.Unsafe().OrderByDescending(keySelector); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in descending order according to a key. + /// + /// The type of the elements in . + /// The type of key returned by . + /// The type of the value returned by . + /// An array of values to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A function to extract a key from a projected element. + /// An to compare keys. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in descending order according to a key. + /// + public static ImmutableArray SelectAndOrderByDescendingAsArray( + this ImmutableArray array, Func selector, Func keySelector, IComparer comparer) + { + var result = array.SelectAsArray(selector); + result.Unsafe().OrderByDescending(keySelector, comparer); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in descending order according to a key. + /// + /// The type of the elements in . + /// The type of key returned by . + /// The type of the value returned by . + /// An array of values to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A function to extract a key from a projected element. + /// A to compare keys. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in descending order according to a key. + /// + public static ImmutableArray SelectAndOrderByDescendingAsArray( + this ImmutableArray array, Func selector, Func keySelector, Comparison comparison) + { + var result = array.SelectAsArray(selector); + result.Unsafe().OrderByDescending(keySelector, comparison); + + return result; + } } diff --git a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/ReadOnlyListExtensions.cs b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/ReadOnlyListExtensions.cs index 01c96def822..468176d1abc 100644 --- a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/ReadOnlyListExtensions.cs +++ b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/ReadOnlyListExtensions.cs @@ -4,77 +4,120 @@ using System.Collections.Immutable; using System.Runtime.InteropServices; using Microsoft.AspNetCore.Razor; -using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.AspNetCore.Razor.Utilities; namespace System.Collections.Generic; internal static class ReadOnlyListExtensions { - public static ImmutableArray SelectAsArray(this IReadOnlyList source, Func selector) + /// + /// Projects each element of an into a new form. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An of values to invoke a transform function on. + /// A transform function to apply to each element. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of . + /// + public static ImmutableArray SelectAsArray(this IReadOnlyList list, Func selector) { - return source switch + var count = list.Count; + if (count == 0) { - [] => [], - [var item] => [selector(item)], - [var item1, var item2] => [selector(item1), selector(item2)], - [var item1, var item2, var item3] => [selector(item1), selector(item2), selector(item3)], - [var item1, var item2, var item3, var item4] => [selector(item1), selector(item2), selector(item3), selector(item4)], - var items => BuildResult(items, selector) - }; + return []; + } - static ImmutableArray BuildResult(IReadOnlyList items, Func selector) + // If the list is a boxed ImmutableArray, it's better to unbox it here and call the SelectAsArray + // extension method that takes an ImmutableArray rather than iterating through the interface. + if (list is ImmutableArray array) { - using var results = new PooledArrayBuilder(capacity: items.Count); + return ImmutableArrayExtensions.SelectAsArray(array, selector); + } - for (var i = 0; i < items.Count; i++) - { - results.Add(selector(items[i])); - } + var result = new TResult[count]; - return results.DrainToImmutable(); + for (var i = 0; i < count; i++) + { + result[i] = selector(list[i]); } + + return ImmutableCollectionsMarshal.AsImmutableArray(result); } - public static T[] ToArray(this IReadOnlyList list) + /// + /// Projects each element of an into a new form by incorporating the element's index. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An of values to invoke a transform function on. + /// + /// A transform function to apply to each element; the second parameter of the function represents the index of the element. + /// + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of . + /// + public static ImmutableArray SelectAsArray(this IReadOnlyList list, Func selector) { - return list switch + var count = list.Count; + if (count == 0) { - [] => [], - [var item] => [item], - [var item1, var item2] => [item1, item2], - [var item1, var item2, var item3] => [item1, item2, item3], - [var item1, var item2, var item3, var item4] => [item1, item2, item3, item4], - var items => BuildResult(items) - }; + return []; + } - static T[] BuildResult(IReadOnlyList items) + // If the list is a boxed ImmutableArray, it's better to unbox it here and call the SelectAsArray + // extension method that takes an ImmutableArray rather than iterating through the interface. + if (list is ImmutableArray array) { - var result = new T[items.Count]; - items.CopyTo(result); + return ImmutableArrayExtensions.SelectAsArray(array, selector); + } + + var result = new TResult[count]; - return result; + for (var i = 0; i < count; i++) + { + result[i] = selector(list[i], i); } + + return ImmutableCollectionsMarshal.AsImmutableArray(result); } - public static ImmutableArray ToImmutableArray(this IReadOnlyList list) + public static T[] ToArray(this IReadOnlyList list) { - return list switch + // If the list is a boxed ImmutableArray, it's better to unbox it here and call through + // the official ImmutableArray.ToArray() extension method. + if (list is ImmutableArray array) { - [] => [], - [var item] => [item], - [var item1, var item2] => [item1, item2], - [var item1, var item2, var item3] => [item1, item2, item3], - [var item1, var item2, var item3, var item4] => [item1, item2, item3, item4], - var items => BuildResult(items) - }; + return Linq.ImmutableArrayExtensions.ToArray(array); + } - static ImmutableArray BuildResult(IReadOnlyList items) - { - var result = items.ToArray(); + return list.Count > 0 + ? CreateArray(list) + : []; + } - return ImmutableCollectionsMarshal.AsImmutableArray(result); + public static ImmutableArray ToImmutableArray(this IReadOnlyList list) + { + // If the list is a boxed ImmutableArray, it's better to unbox it here and just return it. + // This is what the official IEnumerable.ToImmutableArray() extension method does. + if (list is ImmutableArray array) + { + return array; } + + return list.Count > 0 + ? ImmutableCollectionsMarshal.AsImmutableArray(CreateArray(list)) + : []; + } + + private static T[] CreateArray(IReadOnlyList list) + { + var result = new T[list.Count]; + CopyTo(list, result); + + return result; } /// @@ -1043,7 +1086,7 @@ public static void CopyTo(this IReadOnlyList list, Span destination) /// Sorts the elements of an in ascending order. /// /// The type of the elements in . - /// An to ordered. + /// An whose elements will be sorted. /// /// Returns a new whose elements are sorted in ascending order. /// @@ -1062,7 +1105,7 @@ public static ImmutableArray OrderAsArray(this IReadOnlyList list) /// Sorts the elements of an in ascending order. /// /// The type of the elements in . - /// An to ordered. + /// An whose elements will be sorted. /// An to compare elements. /// /// Returns a new whose elements are sorted in ascending order. @@ -1082,7 +1125,7 @@ public static ImmutableArray OrderAsArray(this IReadOnlyList list, ICom /// Sorts the elements of an in ascending order. /// /// The type of the elements in . - /// An to ordered. + /// An whose elements will be sorted. /// An to compare elements. /// /// Returns a new whose elements are sorted in ascending order. @@ -1102,7 +1145,7 @@ public static ImmutableArray OrderAsArray(this IReadOnlyList list, Comp /// Sorts the elements of an in descending order. /// /// The type of the elements in . - /// An to ordered. + /// An whose elements will be sorted. /// /// Returns a new whose elements are sorted in descending order. /// @@ -1121,7 +1164,7 @@ public static ImmutableArray OrderDescendingAsArray(this IReadOnlyList /// Sorts the elements of an in descending order. /// /// The type of the elements in . - /// An to ordered. + /// An whose elements will be sorted. /// An to compare elements. /// /// Returns a new whose elements are sorted in descending order. @@ -1141,7 +1184,7 @@ public static ImmutableArray OrderDescendingAsArray(this IReadOnlyList /// Sorts the elements of an in descending order. /// /// The type of the elements in . - /// An to ordered. + /// An whose elements will be sorted. /// An to compare elements. /// /// Returns a new whose elements are sorted in descending order. @@ -1162,7 +1205,7 @@ public static ImmutableArray OrderDescendingAsArray(this IReadOnlyList /// /// The type of the elements in . /// The type of key returned by . - /// An to ordered. + /// An whose elements will be sorted. /// A function to extract a key from an element. /// /// Returns a new whose elements are sorted in ascending order according to a key. @@ -1184,7 +1227,7 @@ public static ImmutableArray OrderByAsArray( /// /// The type of the elements in . /// The type of key returned by . - /// An to ordered. + /// An whose elements will be sorted. /// A function to extract a key from an element. /// An to compare keys. /// @@ -1207,7 +1250,7 @@ public static ImmutableArray OrderByAsArray( /// /// The type of the elements in . /// The type of key returned by . - /// An to ordered. + /// An whose elements will be sorted. /// A function to extract a key from an element. /// An to compare keys. /// @@ -1230,7 +1273,7 @@ public static ImmutableArray OrderByAsArray( /// /// The type of the elements in . /// The type of key returned by . - /// An to ordered. + /// An whose elements will be sorted. /// A function to extract a key from an element. /// /// Returns a new whose elements are sorted in descending order according to a key. @@ -1252,7 +1295,7 @@ public static ImmutableArray OrderByDescendingAsArray( /// /// The type of the elements in . /// The type of key returned by . - /// An to ordered. + /// An whose elements will be sorted. /// A function to extract a key from an element. /// An to compare keys. /// @@ -1275,7 +1318,7 @@ public static ImmutableArray OrderByDescendingAsArray( /// /// The type of the elements in . /// The type of key returned by . - /// An to ordered. + /// An whose elements will be sorted. /// A function to extract a key from an element. /// An to compare keys. /// @@ -1324,4 +1367,262 @@ private static ImmutableArray OrderByAsArrayCore( return ImmutableCollectionsMarshal.AsImmutableArray(newArray); } + + /// + /// Projects each element of an into a new form and sorts them in ascending order. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in ascending order. + /// + public static ImmutableArray SelectAndOrderAsArray(this IReadOnlyList list, Func selector) + { + var result = list.SelectAsArray(selector); + result.Unsafe().Order(); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in ascending order. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// An to compare elements. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in ascending order. + /// + public static ImmutableArray SelectAndOrderAsArray( + this IReadOnlyList list, Func selector, IComparer comparer) + { + var result = list.SelectAsArray(selector); + result.Unsafe().Order(comparer); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in ascending order. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// An to compare elements. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in ascending order. + /// + public static ImmutableArray SelectAndOrderAsArray( + this IReadOnlyList list, Func selector, Comparison comparison) + { + var result = list.SelectAsArray(selector); + result.Unsafe().Order(comparison); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in descending order. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in decending order. + /// + public static ImmutableArray SelectAndOrderDescendingAsArray(this IReadOnlyList list, Func selector) + { + var result = list.SelectAsArray(selector); + result.Unsafe().OrderDescending(); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in descending order. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// An to compare elements. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in decending order. + /// + public static ImmutableArray SelectAndOrderDescendingAsArray( + this IReadOnlyList list, Func selector, IComparer comparer) + { + var result = list.SelectAsArray(selector); + result.Unsafe().OrderDescending(comparer); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in descending order. + /// + /// The type of the elements in . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// An to compare elements. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in decending order. + /// + public static ImmutableArray SelectAndOrderDescendingAsArray( + this IReadOnlyList list, Func selector, Comparison comparison) + { + var result = list.SelectAsArray(selector); + result.Unsafe().OrderDescending(comparison); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in ascending order according to a key. + /// + /// The type of the elements in . + /// The type of key returned by . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A function to extract a key from a projected element. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in ascending order according to a key. + /// + public static ImmutableArray SelectAndOrderByAsArray( + this IReadOnlyList list, Func selector, Func keySelector) + { + var result = list.SelectAsArray(selector); + result.Unsafe().OrderBy(keySelector); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in ascending order according to a key. + /// + /// The type of the elements in . + /// The type of key returned by . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A function to extract a key from a projected element. + /// An to compare keys. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in ascending order according to a key. + /// + public static ImmutableArray SelectAndOrderByAsArray( + this IReadOnlyList list, Func selector, Func keySelector, IComparer comparer) + { + var result = list.SelectAsArray(selector); + result.Unsafe().OrderBy(keySelector, comparer); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in ascending order according to a key. + /// + /// The type of the elements in . + /// The type of key returned by . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A function to extract a key from a projected element. + /// An to compare keys. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in ascending order according to a key. + /// + public static ImmutableArray SelectAndOrderByAsArray( + this IReadOnlyList list, Func selector, Func keySelector, Comparison comparison) + { + var result = list.SelectAsArray(selector); + result.Unsafe().OrderBy(keySelector, comparison); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in descending order according to a key. + /// + /// The type of the elements in . + /// The type of key returned by . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A function to extract a key from a projected element. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in descending order according to a key. + /// + public static ImmutableArray SelectAndOrderByDescendingAsArray( + this IReadOnlyList list, Func selector, Func keySelector) + { + var result = list.SelectAsArray(selector); + result.Unsafe().OrderByDescending(keySelector); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in descending order according to a key. + /// + /// The type of the elements in . + /// The type of key returned by . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A function to extract a key from a projected element. + /// An to compare keys. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in descending order according to a key. + /// + public static ImmutableArray SelectAndOrderByDescendingAsArray( + this IReadOnlyList list, Func selector, Func keySelector, IComparer comparer) + { + var result = list.SelectAsArray(selector); + result.Unsafe().OrderByDescending(keySelector, comparer); + + return result; + } + + /// + /// Projects each element of an into a new form and sorts them in descending order according to a key. + /// + /// The type of the elements in . + /// The type of key returned by . + /// The type of the value returned by . + /// An of elements to invoke a transform function on and sort. + /// A transform function to apply to each element. + /// A function to extract a key from a projected element. + /// An to compare keys. + /// + /// Returns a new whose elements are the result of invoking the transform function + /// on each element of and sorted in descending order according to a key. + /// + public static ImmutableArray SelectAndOrderByDescendingAsArray( + this IReadOnlyList list, Func selector, Func keySelector, Comparison comparison) + { + var result = list.SelectAsArray(selector); + result.Unsafe().OrderByDescending(keySelector, comparison); + + return result; + } } diff --git a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Threading/AsyncLazy`1.cs b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Threading/AsyncLazy`1.cs index d3a01d5746f..66b6dbd8496 100644 --- a/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Threading/AsyncLazy`1.cs +++ b/src/razor/src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/Threading/AsyncLazy`1.cs @@ -285,7 +285,9 @@ private void StartAsynchronousComputation( { using (TakeLock(CancellationToken.None)) { +#pragma warning disable CA2025 // task is already completed so we're not disposing too early here task = GetCachedValueAndCacheThisValueIfNoneCached_NoLock(task); +#pragma warning restore } requestToCompleteSynchronously.CompleteFromTask(task); diff --git a/src/roslyn-analyzers/.github/policies/breaking-change.yml b/src/roslyn-analyzers/.github/policies/breaking-change.yml new file mode 100644 index 00000000000..28e2be4d91f --- /dev/null +++ b/src/roslyn-analyzers/.github/policies/breaking-change.yml @@ -0,0 +1,31 @@ +name: breaking-change +description: Automatically apply the label and comment needed to ensure breaking changes are documented properly when the 'breaking-change' label is applied. +resource: repository +configuration: + resourceManagementConfiguration: + eventResponderTasks: + - description: Add breaking change doc instructions to issue + if: + - payloadType: Issues + - labelAdded: + label: breaking-change + then: + - addReply: + reply: Refer to the [.NET SDK breaking change guidelines](https://github.com/dotnet/sdk/blob/main/documentation/project-docs/breaking-change-guidelines.md#required-process-for-all-net-sdk-breaking-changes) + - description: Add breaking change instructions to PR + if: + - payloadType: Pull_Request + - labelAdded: + label: breaking-change + then: + - addLabel: + label: needs-breaking-change-doc-created + - addReply: + reply: "Added `needs-breaking-change-doc-created` label because this PR\ + \ has the `breaking-change` label. \n\n\nWhen you commit this breaking\ + \ change:\n\n\n1. [ ] Create and link to this PR and the issue a matching\ + \ issue in the dotnet/docs repo using the [breaking change documentation\ + \ template](https://aka.ms/dotnet/docs/new-breaking-change-issue), then\ + \ remove this `needs-breaking-change-doc-created` label.\n\n2. [ ] Ask\ + \ a committer to mail the `.NET SDK Breaking Change Notification` email\ + \ list.\n\n\nYou can refer to the [.NET SDK breaking change guidelines](https://github.com/dotnet/sdk/blob/main/documentation/project-docs/breaking-change-guidelines.md)" diff --git a/src/roslyn-analyzers/eng/AfterSolutionBuild.targets b/src/roslyn-analyzers/eng/AfterSolutionBuild.targets index a59291c9d0e..6989a2d56c5 100644 --- a/src/roslyn-analyzers/eng/AfterSolutionBuild.targets +++ b/src/roslyn-analyzers/eng/AfterSolutionBuild.targets @@ -1,4 +1,3 @@ - diff --git a/src/roslyn-analyzers/eng/CodeCoverage.proj b/src/roslyn-analyzers/eng/CodeCoverage.proj index a927075d8f6..7320ec09218 100644 --- a/src/roslyn-analyzers/eng/CodeCoverage.proj +++ b/src/roslyn-analyzers/eng/CodeCoverage.proj @@ -1,4 +1,5 @@ + C# @@ -37,4 +38,5 @@ + \ No newline at end of file diff --git a/src/roslyn-analyzers/eng/GenerateAnalyzerNuspec.targets b/src/roslyn-analyzers/eng/GenerateAnalyzerNuspec.targets index 6555e7229cf..99c19c39802 100644 --- a/src/roslyn-analyzers/eng/GenerateAnalyzerNuspec.targets +++ b/src/roslyn-analyzers/eng/GenerateAnalyzerNuspec.targets @@ -1,5 +1,5 @@ - - + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) @@ -165,4 +165,5 @@ + diff --git a/src/roslyn-analyzers/eng/Publishing.props b/src/roslyn-analyzers/eng/Publishing.props index 2d3ce7dde23..844ae55fb98 100644 --- a/src/roslyn-analyzers/eng/Publishing.props +++ b/src/roslyn-analyzers/eng/Publishing.props @@ -1,4 +1,5 @@ + true diff --git a/src/roslyn-analyzers/eng/Signing.props b/src/roslyn-analyzers/eng/Signing.props index 586fe4875a2..36b4accde16 100644 --- a/src/roslyn-analyzers/eng/Signing.props +++ b/src/roslyn-analyzers/eng/Signing.props @@ -1,5 +1,7 @@ + true + diff --git a/src/roslyn-analyzers/eng/SourceBuildPrebuiltBaseline.xml b/src/roslyn-analyzers/eng/SourceBuildPrebuiltBaseline.xml deleted file mode 100644 index afc90c12426..00000000000 --- a/src/roslyn-analyzers/eng/SourceBuildPrebuiltBaseline.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/src/roslyn-analyzers/eng/Testing.targets b/src/roslyn-analyzers/eng/Testing.targets index f7d8c945ac4..ebfb5da816b 100644 --- a/src/roslyn-analyzers/eng/Testing.targets +++ b/src/roslyn-analyzers/eng/Testing.targets @@ -1,4 +1,5 @@ + $(TestRunnerAdditionalArguments) --blame $(TestRunnerAdditionalArguments) --blame-hang-dump-type full @@ -11,4 +12,5 @@ $(TestRunnerAdditionalArguments) --test-adapter-path "$(Pkgcoverlet_collector)/build/netstandard1.0" $(TestRunnerAdditionalArguments) --settings "$(RepoRoot)/eng/CodeCoverage.runsettings" + diff --git a/src/roslyn-analyzers/eng/Version.Details.xml b/src/roslyn-analyzers/eng/Version.Details.xml index 67c4e3a4313..314b6894550 100644 --- a/src/roslyn-analyzers/eng/Version.Details.xml +++ b/src/roslyn-analyzers/eng/Version.Details.xml @@ -1,38 +1,20 @@ - + https://github.com/dotnet/roslyn ae1fff344d46976624e68ae17164e0607ab68b10 - - - https://github.com/dotnet/source-build-reference-packages - e798ac579db6cdcb2505e6cf39141fd508e407d1 - - - - - https://github.com/dotnet/source-build-externals - de4dda48d0cf31e13182bc24107b2246c61ed483 - - - + https://github.com/dotnet/dotnet - 919f64d9fd105eda6d412b926d9c20951383150f - - - - https://github.com/dotnet/arcade - 37f732fbfa006386f89a16be417278ea4fee375e - + 78c5fa9a48d469a19ab5a61c16c955c1f370b5be - + https://github.com/dotnet/dotnet - 919f64d9fd105eda6d412b926d9c20951383150f + 78c5fa9a48d469a19ab5a61c16c955c1f370b5be https://github.com/dotnet/roslyn diff --git a/src/roslyn-analyzers/eng/Versions.props b/src/roslyn-analyzers/eng/Versions.props index fe4e4c0e8f5..f50feaff0a5 100644 --- a/src/roslyn-analyzers/eng/Versions.props +++ b/src/roslyn-analyzers/eng/Versions.props @@ -75,7 +75,7 @@ 1.1.2-beta1.24314.1 - 10.0.0-beta.25225.102 + 10.0.0-beta.25229.109 0.13.0 2.14.1 diff --git a/src/roslyn-analyzers/eng/common/core-templates/steps/source-index-stage1-publish.yml b/src/roslyn-analyzers/eng/common/core-templates/steps/source-index-stage1-publish.yml index 473a22c4719..99c2326fc19 100644 --- a/src/roslyn-analyzers/eng/common/core-templates/steps/source-index-stage1-publish.yml +++ b/src/roslyn-analyzers/eng/common/core-templates/steps/source-index-stage1-publish.yml @@ -1,6 +1,6 @@ parameters: - sourceIndexUploadPackageVersion: 2.0.0-20240522.1 - sourceIndexProcessBinlogPackageVersion: 1.0.1-20240522.1 + sourceIndexUploadPackageVersion: 2.0.0-20250425.2 + sourceIndexProcessBinlogPackageVersion: 1.0.1-20250425.2 sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json binlogPath: artifacts/log/Debug/Build.binlog diff --git a/src/roslyn-analyzers/global.json b/src/roslyn-analyzers/global.json index b369119bf00..5e2b0b4f4bb 100644 --- a/src/roslyn-analyzers/global.json +++ b/src/roslyn-analyzers/global.json @@ -18,6 +18,6 @@ "rollForward": "patch" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25225.102" + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25229.109" } } diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md b/src/roslyn-analyzers/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md index 1daebbc0fbf..cbec76689a7 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md @@ -9,3 +9,4 @@ CA1874 | Performance | Info | UseRegexMembers, [Documentation](https://learn.mic CA1875 | Performance | Info | UseRegexMembers, [Documentation](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1875) CA2023 | Reliability | Warning | LoggerMessageDefineAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2023) CA2024 | Reliability | Warning | DoNotUseEndOfStreamInAsyncMethods, [Documentation](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2024) +CA2025 | Reliability | Warning | DoNotPassDisposablesIntoUnawaitedTasksAnalyzer, [Documentation](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2025) diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/MicrosoftCodeQualityAnalyzersResources.resx b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/MicrosoftCodeQualityAnalyzersResources.resx index 4c8b05f52af..cd2dd357931 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/MicrosoftCodeQualityAnalyzersResources.resx +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/MicrosoftCodeQualityAnalyzersResources.resx @@ -1312,6 +1312,15 @@ Because an application's API isn't typically referenced from outside the assembly, types can be made internal - Consider making public types internal + Consider making public types internal + + + Do not pass 'IDisposable' instances into unawaited tasks + + + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + + + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. \ No newline at end of file diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/QualityGuidelines/DoNotPassDisposablesIntoUnawaitedTasks.cs b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/QualityGuidelines/DoNotPassDisposablesIntoUnawaitedTasks.cs new file mode 100644 index 00000000000..fed3f389a12 --- /dev/null +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/QualityGuidelines/DoNotPassDisposablesIntoUnawaitedTasks.cs @@ -0,0 +1,224 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. + +using System; +using System.Linq; +using System.Collections.Generic; +using System.Collections.Immutable; +using Analyzer.Utilities; +using Analyzer.Utilities.Extensions; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; + +namespace Microsoft.CodeQuality.Analyzers.QualityGuidelines +{ + using static MicrosoftCodeQualityAnalyzersResources; + + /// + /// CA2025: + /// + [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] + public sealed class DoNotPassDisposablesIntoUnawaitedTasksAnalyzer : DiagnosticAnalyzer + { + internal const string RuleId = "CA2025"; + + internal static readonly DiagnosticDescriptor Rule = DiagnosticDescriptorHelper.Create( + RuleId, + CreateLocalizableResourceString(nameof(DoNotPassDisposablesIntoUnawaitedTasksTitle)), + CreateLocalizableResourceString(nameof(DoNotPassDisposablesIntoUnawaitedTasksMessage)), + DiagnosticCategory.Reliability, + RuleLevel.BuildWarning, + description: CreateLocalizableResourceString(nameof(DoNotPassDisposablesIntoUnawaitedTasksDescription)), + isPortedFxCopRule: false, + isDataflowRule: false); + + public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.EnableConcurrentExecution(); + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + + context.RegisterOperationAction(context => + { + var provider = WellKnownTypeProvider.GetOrCreate(context.Compilation); + if (!provider.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemIDisposable, out var iDisposable)) + { + return; + } + + var invocation = (IInvocationOperation)context.Operation; + + // Only care about tasks + if (!invocation.IsTask()) + { + return; + } + + // Ignore if awaited or run synchronously with task.Result or task.Wait() + if (invocation.IsAwaited()) + { + return; + } + + // Only care about invocations that receive IDisposable's as args + if (!invocation.Arguments.AnyWhere(arg => arg.Parameter?.Type?.AllInterfaces is { Length: > 0 } allInterfaces && + allInterfaces.Any(i => i.ToString() == WellKnownTypeNames.SystemIDisposable), out var disposableArguments)) + { + return; + } + + var referencedDisposableArgs = GetReferencedDisposableArguments(invocation, disposableArguments); + + foreach (var referencedArg in referencedDisposableArgs) + { + context.ReportDiagnostic(referencedArg.CreateDiagnostic(Rule)); + } + }, OperationKind.Invocation); + } + + private static IEnumerable GetReferencedDisposableArguments(IInvocationOperation invocation, + IList disposableArguments) + { + // Get the references of the disposable arguments + var disposableArgumentReferences = GetLocalReferencesFromArguments(disposableArguments).ToList(); + + // We use the inner method body only for checking disposable usage + IOperation? containingBlock = invocation.GetAncestor(OperationKind.MethodBody); + // In VB the real containing block is higher, especially if there are using blocks + containingBlock ??= invocation.GetRoot(); + + var descendants = containingBlock.Descendants().ToList(); + var localReferences = descendants.OfType(); + + // Get declarator for invocation and verify the invocation is the retrieved declarator's initializer value + var declaratorForInvocation = invocation.GetAncestor(OperationKind.VariableDeclarator, + decl => decl.Initializer?.Value == invocation); + // VB has slightly different structure for getting to declarator + declaratorForInvocation ??= invocation.GetAncestor(OperationKind.VariableDeclaration)? + .Declarators.FirstOrDefault(); + + bool contextContainsDisposeCalls = localReferences.AnyWhere(r => r.Parent + is IInvocationOperation { TargetMethod.Name: nameof(IDisposable.Dispose) }, out var disposeCalls); + + // We can skip reporting ONLY if the disposable arguments are disposed AFTER the task is awaited + if (declaratorForInvocation is { } && contextContainsDisposeCalls) + { + var disposeCallsThatDisposeReferencedArgs = disposeCalls.Where(disposeCall => + disposableArgumentReferences.Any(disposableArg => disposeCall.Local.Equals(disposableArg.Local))); + + // See if the task is referenced and awaited elsewhere + var awaitedInvocationReference = localReferences.FirstOrDefault(r => r.IsAwaited() && + r.Local.Equals(declaratorForInvocation.Symbol)); + if (awaitedInvocationReference is not null) + { + // Check if all disposals of arguments into the task are after the task is awaited + bool eachDisposeIsAferTaskIsAwaited = true; + foreach (var disposeCall in disposeCallsThatDisposeReferencedArgs) + { + if (disposeCall.Syntax.SpanStart < awaitedInvocationReference.Syntax.SpanStart) + { + eachDisposeIsAferTaskIsAwaited = false; + break; + } + } + + // Do not report if arguments are disposed after the task is awaited elsewhere + if (eachDisposeIsAferTaskIsAwaited) + { + return new List(0); + } + } + } + + var referencedDisposableArgs = new List(); + + // Check if the disposable argument references originate from using statements + if (descendants.OfType().ToList() is { Count: > 0 } usingBlocks) + { + List usingLocals = new(); + usingBlocks.ForEach(u => usingLocals.AddRange(u.Locals)); + + // Add all argument references that originate from using statements + referencedDisposableArgs.AddRange(disposableArgumentReferences.Where(disposableRef => + { + foreach (var usingLocal in usingLocals) + { + if (usingLocal.Equals(disposableRef)) + { + return true; + } + } + + return false; + })); + } + else if (!descendants.OfType().Any() && + !contextContainsDisposeCalls) + { + // If we have no using blocks/statements and no Dispose calls, nothing to report + return new List(0); + } + + // Add all references to disposable args not already caught with previous logic + referencedDisposableArgs.AddRange(localReferences.Intersect(disposableArgumentReferences)); + + return referencedDisposableArgs; + } + + private static IEnumerable GetLocalReferencesFromArguments(IList args) + { + return args.Select(disposableArg => + { + // Either a converted reference + if (disposableArg.Value is IConversionOperation conversion + && conversion.Operand is ILocalReferenceOperation convertedLocalReference) + { + return convertedLocalReference; + } + + // Or an unconverted reference + return (disposableArg.Value as ILocalReferenceOperation)!; + }); + } + } + + internal static class TaskOperationExtensions + { + public static bool IsAwaited(this IOperation op) + { + return op.GetAncestor(OperationKind.Await) is not null || + op.Parent is IInvocationOperation { TargetMethod.Name: "Wait" } or + IPropertyReferenceOperation { Property.Name: "Result" }; + } + + public static bool IsTask(this IOperation op) + { + return op.Type?.ToString() == WellKnownTypeNames.SystemThreadingTasksTask || + op.Type?.BaseType?.ToString() == WellKnownTypeNames.SystemThreadingTasksTask; + } + } + + internal static class EnumerableExtensions + { + public static bool AnyWhere(this IEnumerable collection, Predicate predicate, out IList matches) + { + bool anyMatches = false; + IEnumerable GetWhere() + { + foreach (var item in collection) + { + if (predicate(item)) + { + anyMatches = true; + yield return item; + } + } + } + + // ToList actually evaluates enumerable so anyMatches will be accurate + matches = [.. GetWhere()]; + return anyMatches; + } + } +} diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.cs.xlf b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.cs.xlf index 0e1beef2446..deae7d0f0bb 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.cs.xlf +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.cs.xlf @@ -207,6 +207,21 @@ Nepřetěžujte operátor rovnosti na odkazových typech + + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + + + + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + + + + Do not pass 'IDisposable' instances into unawaited tasks + Do not pass 'IDisposable' instances into unawaited tasks + + Passing types by reference (using out or ref) requires experience with pointers, understanding how value types and reference types differ, and handling methods that have multiple return values. Also, the difference between out and ref parameters is not widely understood. Předávání typů podle odkazu (jako out nebo ref) vyžaduje zkušenost s ukazateli, porozumění rozdílu mezi hodnotovými a odkazovými typy a obeznámenost s metodami s více návratovými hodnotami. Navíc není široce rozšířeno chápání rozdílu mezi parametry out a ref. diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.de.xlf b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.de.xlf index f4cb58c9416..435ecaf7ed4 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.de.xlf +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.de.xlf @@ -207,6 +207,21 @@ Gleichheitsoperator für Verweistypen nicht überladen + + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + + + + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + + + + Do not pass 'IDisposable' instances into unawaited tasks + Do not pass 'IDisposable' instances into unawaited tasks + + Passing types by reference (using out or ref) requires experience with pointers, understanding how value types and reference types differ, and handling methods that have multiple return values. Also, the difference between out and ref parameters is not widely understood. Das Übergeben von Typen als Verweis (mit "out" oder "ref") erfordert Erfahrung mit Zeigern, den Unterschieden zwischen Werttypen und Verweistypen sowie der Verarbeitung von Methoden mit mehreren Rückgabewerten. Auch der Unterschied zwischen den Parametern "out" und "ref" ist nicht allgemein geläufig. diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.es.xlf b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.es.xlf index a2562502e76..b8b6689bf40 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.es.xlf +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.es.xlf @@ -207,6 +207,21 @@ No sobrecargar el operador de igualdad en los tipos de referencia + + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + + + + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + + + + Do not pass 'IDisposable' instances into unawaited tasks + Do not pass 'IDisposable' instances into unawaited tasks + + Passing types by reference (using out or ref) requires experience with pointers, understanding how value types and reference types differ, and handling methods that have multiple return values. Also, the difference between out and ref parameters is not widely understood. Para pasar tipos por referencia (mediante out o ref) se necesita tener experiencia con punteros, comprender en qué se diferencian los tipos de valor y los tipos de referencia y saber usar métodos que tengan varios valores devueltos. Además, la diferencia entre los parámetros out y ref no se ha entendido del todo. diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.fr.xlf b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.fr.xlf index 5b9321ae800..3f18488ee43 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.fr.xlf +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.fr.xlf @@ -207,6 +207,21 @@ Ne pas surcharger l'opérateur d'égalité sur les types référence + + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + + + + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + + + + Do not pass 'IDisposable' instances into unawaited tasks + Do not pass 'IDisposable' instances into unawaited tasks + + Passing types by reference (using out or ref) requires experience with pointers, understanding how value types and reference types differ, and handling methods that have multiple return values. Also, the difference between out and ref parameters is not widely understood. Le passage de types par référence (via out ou ref) nécessite une bonne connaissance des pointeurs, une bonne compréhension des différences entre les types valeur et les types référence ainsi qu'une certaine expérience de la gestion des méthodes ayant plusieurs valeurs de retour. En effet, la différence entre les paramètres out et ref n'est pas comprise par tout le monde. diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.it.xlf b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.it.xlf index f39db267b0c..38bb65326b6 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.it.xlf +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.it.xlf @@ -207,6 +207,21 @@ Non eseguire l'overload dell'operatore di uguaglianza per i tipi riferimento + + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + + + + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + + + + Do not pass 'IDisposable' instances into unawaited tasks + Do not pass 'IDisposable' instances into unawaited tasks + + Passing types by reference (using out or ref) requires experience with pointers, understanding how value types and reference types differ, and handling methods that have multiple return values. Also, the difference between out and ref parameters is not widely understood. Oltre all'esperienza con i puntatori, per passare tipi per riferimento (con out o ref), è necessario comprendere le differenze tra tipi valore e tipi riferimento e gestire i metodi con più valori restituiti. Anche la differenza tra parametri out e ref non è del tutto compresa. diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.ja.xlf b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.ja.xlf index b1aa91d6cc5..973755353e6 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.ja.xlf +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.ja.xlf @@ -207,6 +207,21 @@ 参照型で、等値演算子をオーバーロードしないでください + + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + + + + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + + + + Do not pass 'IDisposable' instances into unawaited tasks + Do not pass 'IDisposable' instances into unawaited tasks + + Passing types by reference (using out or ref) requires experience with pointers, understanding how value types and reference types differ, and handling methods that have multiple return values. Also, the difference between out and ref parameters is not widely understood. (out または ref を使用して) 型を参照によって渡すには、ポインターの使用経験、値型と参照型の違いの理解、および複数の戻り値を持つメソッドの処理が必要です。また、out および ref パラメーターの違いはあまり理解されていません。 diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.ko.xlf b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.ko.xlf index d551ce314a4..51fb7e47a23 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.ko.xlf +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.ko.xlf @@ -207,6 +207,21 @@ 참조 형식에 같음 연산자를 오버로드하지 마세요. + + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + + + + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + + + + Do not pass 'IDisposable' instances into unawaited tasks + Do not pass 'IDisposable' instances into unawaited tasks + + Passing types by reference (using out or ref) requires experience with pointers, understanding how value types and reference types differ, and handling methods that have multiple return values. Also, the difference between out and ref parameters is not widely understood. out 또는 ref를 사용하여 참조로 형식을 전달하려면 포인터 사용 경험이 있고, 값 형식과 참조 형식의 차이점을 알고 있으며, 반환 값이 여러 개인 메서드를 처리해야 합니다. 또한 out 매개 변수와 ref 매개 변수의 차이점은 널리 알려져 있지 않습니다. diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.pl.xlf b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.pl.xlf index b6d5298bd58..1e08405361d 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.pl.xlf +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.pl.xlf @@ -207,6 +207,21 @@ Nie przeciążaj operatora równości w typach referencyjnych + + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + + + + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + + + + Do not pass 'IDisposable' instances into unawaited tasks + Do not pass 'IDisposable' instances into unawaited tasks + + Passing types by reference (using out or ref) requires experience with pointers, understanding how value types and reference types differ, and handling methods that have multiple return values. Also, the difference between out and ref parameters is not widely understood. Przekazywanie typów przez odwołanie (zastosowanie parametrów „out” lub „ref”) wymaga doświadczenia w pracy ze wskaźnikami, rozumienia różnic między typami wartości i typami odwołań oraz umiejętności stosowania metod z wieloma wartościami zwracanymi. Ponadto różnice między parametrami „out” i „ref” nie są powszechnie zrozumiałe. diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.pt-BR.xlf b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.pt-BR.xlf index dab1787064b..2f502ec7613 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.pt-BR.xlf +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.pt-BR.xlf @@ -207,6 +207,21 @@ Não sobrecarregar o operador de igualdade em tipos de referência + + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + + + + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + + + + Do not pass 'IDisposable' instances into unawaited tasks + Do not pass 'IDisposable' instances into unawaited tasks + + Passing types by reference (using out or ref) requires experience with pointers, understanding how value types and reference types differ, and handling methods that have multiple return values. Also, the difference between out and ref parameters is not widely understood. A passagem de tipos por referência (usando 'out' ou 'ref') exige experiência com ponteiros, o entendimento da diferença entre os tipos de valor e de referência e a manipulação de métodos com vários valores retornados. Além disso, não há um amplo entendimento sobre a diferença entre os parâmetros out e ref. diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.ru.xlf b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.ru.xlf index 25c049594e0..50c44ac83c7 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.ru.xlf +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.ru.xlf @@ -207,6 +207,21 @@ Не перегружайте оператор равенства для ссылочных типов + + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + + + + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + + + + Do not pass 'IDisposable' instances into unawaited tasks + Do not pass 'IDisposable' instances into unawaited tasks + + Passing types by reference (using out or ref) requires experience with pointers, understanding how value types and reference types differ, and handling methods that have multiple return values. Also, the difference between out and ref parameters is not widely understood. Для передачи типов по ссылке (с использованием "out" или "ref") необходим опыт работы с указателями, понимание различий между типами значений и ссылочными типами, а также использование методов с несколькими возвращаемыми значениями. Кроме того, разница между параметрами "out" и "ref" не является очевидной. diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.tr.xlf b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.tr.xlf index c4986a6610f..698076e5fbe 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.tr.xlf +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.tr.xlf @@ -207,6 +207,21 @@ Eşitlik işlecini başvuru türlerinde aşırı yüklemeyin + + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + + + + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + + + + Do not pass 'IDisposable' instances into unawaited tasks + Do not pass 'IDisposable' instances into unawaited tasks + + Passing types by reference (using out or ref) requires experience with pointers, understanding how value types and reference types differ, and handling methods that have multiple return values. Also, the difference between out and ref parameters is not widely understood. Türleri başvuruya göre geçirmek (out veya ref kullanılarak) için işaretçiler konusunda deneyim sahibi olmak, değer ve başvuru türleri arasındaki farkları anlamak ve birden çok dönüş değeri içeren metotları işlemeyi bilmek gerekir. Ayrıca out ve ref parametreleri arasındaki fark genelde kapsamlı bir şekilde anlaşılmaz. diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.zh-Hans.xlf b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.zh-Hans.xlf index cf15e5007d8..d0158c84d71 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.zh-Hans.xlf +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.zh-Hans.xlf @@ -207,6 +207,21 @@ 不要对引用类型重载相等运算符 + + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + + + + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + + + + Do not pass 'IDisposable' instances into unawaited tasks + Do not pass 'IDisposable' instances into unawaited tasks + + Passing types by reference (using out or ref) requires experience with pointers, understanding how value types and reference types differ, and handling methods that have multiple return values. Also, the difference between out and ref parameters is not widely understood. 要按引用传递类型(使用 out 或 ref),需具备指针方面的经验、了解值类型和引用类型之间的区别,并处理具有多个返回值的方法。此外,out 和 ref 参数之间的差异未被广泛理解。 diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.zh-Hant.xlf b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.zh-Hant.xlf index 554bef9c173..6b76128cad1 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.zh-Hant.xlf +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.CodeQuality.Analyzers/xlf/MicrosoftCodeQualityAnalyzersResources.zh-Hant.xlf @@ -207,6 +207,21 @@ 請勿多載參考型別上的等號比較運算子 + + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + + + + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + Ensure tasks using 'IDisposable' instances complete before the instances are disposed + + + + Do not pass 'IDisposable' instances into unawaited tasks + Do not pass 'IDisposable' instances into unawaited tasks + + Passing types by reference (using out or ref) requires experience with pointers, understanding how value types and reference types differ, and handling methods that have multiple return values. Also, the difference between out and ref parameters is not widely understood. 藉傳址傳遞類型 (使用 out 或 ref) 需有指標經驗、了解實值型別與參考型別之間的差異,以及處理具有多個傳回值的方法。而且,大家普遍不了解 out 與 ref 參數之間的差異。 diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/DoNotCallEnumerableCastOrOfTypeWithIncompatibleTypesAnalyzer.cs b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/DoNotCallEnumerableCastOrOfTypeWithIncompatibleTypesAnalyzer.cs index bc3dda13299..6770beb4505 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/DoNotCallEnumerableCastOrOfTypeWithIncompatibleTypesAnalyzer.cs +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/DoNotCallEnumerableCastOrOfTypeWithIncompatibleTypesAnalyzer.cs @@ -216,16 +216,40 @@ static bool CastWillAlwaysFail(ITypeSymbol castFrom, ITypeSymbol castTo) return false; } - static bool IsUnconstrainedTypeParameter(ITypeParameterSymbol typeParameterSymbol) - => !typeParameterSymbol.HasValueTypeConstraint - && typeParameterSymbol.ConstraintTypes.IsEmpty; - // because object is a reference type the 'class' reference type constraint - // doesn't actually constrain unless a type is specified too - // not implemented: - // NotNullConstraint - // ConstructorConstraint - // UnmanagedTypeConstraint - // Nullability annotations + static bool CastToTypeParamWillAlwaysFail(ITypeSymbol castFrom, ITypeParameterSymbol castToTypeParam) + { + if (castToTypeParam.HasValueTypeConstraint + && ValueTypeConstraintImpossible(castFrom)) + { + return true; + } + + // because object is a reference type the 'class' reference type constraint + // doesn't actually constrain unless a type is specified too + // not implemented: + // NotNullConstraint + // ConstructorConstraint + // UnmanagedTypeConstraint + // Nullability annotations + + if (castToTypeParam.ConstraintTypes.Any(constraintType => CastWillAlwaysFail(castFrom, constraintType))) + { + return true; + } + + return false; + } + + static bool ValueTypeConstraintImpossible(ITypeSymbol t) + { + if (t.TypeKind == TypeKind.Class) + { + return t.SpecialType is not SpecialType.System_Enum + and not SpecialType.System_ValueType; + } + + return false; + } switch (castFrom.TypeKind, castTo.TypeKind) { @@ -235,42 +259,25 @@ static bool IsUnconstrainedTypeParameter(ITypeParameterSymbol typeParameterSymbo case (TypeKind.TypeParameter, _): var castFromTypeParam = (ITypeParameterSymbol)castFrom; - if (IsUnconstrainedTypeParameter(castFromTypeParam)) - { - return false; - } - if (castFromTypeParam.ConstraintTypes.Any(constraintType => CastWillAlwaysFail(constraintType, castTo))) { return true; } if (castFromTypeParam.HasValueTypeConstraint - && castTo.TypeKind == TypeKind.Class) - { - return true; - } - - return false; - case (_, TypeKind.TypeParameter): - var castToTypeParam = (ITypeParameterSymbol)castTo; - if (IsUnconstrainedTypeParameter(castToTypeParam)) - { - return false; - } - - if (castToTypeParam.ConstraintTypes.Any(constraintType => CastWillAlwaysFail(castFrom, constraintType))) + && ValueTypeConstraintImpossible(castTo)) { return true; } - if (castToTypeParam.HasValueTypeConstraint - && castFrom.TypeKind == TypeKind.Class) + if (castTo.TypeKind == TypeKind.TypeParameter) { - return true; + return CastToTypeParamWillAlwaysFail(castFrom, (ITypeParameterSymbol)castTo); } return false; + case (_, TypeKind.TypeParameter): + return CastToTypeParamWillAlwaysFail(castFrom, (ITypeParameterSymbol)castTo); case (TypeKind.Class, TypeKind.Class): return !castFromParam.DerivesFrom(castToParam) diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethods.cs b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethods.cs index 10b207c792c..a9447b41743 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethods.cs +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethods.cs @@ -355,12 +355,12 @@ public StringFormatInfo(Compilation compilation) String = @string; Object = compilation.GetSpecialType(SpecialType.System_Object); - StringSyntaxAttribute = compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemDiagnosticsCodeAnalysisStringSyntaxAttributeName); + StringSyntaxAttributes = compilation.GetTypesByMetadataName(WellKnownTypeNames.SystemDiagnosticsCodeAnalysisStringSyntaxAttributeName); } public INamedTypeSymbol String { get; } public INamedTypeSymbol Object { get; } - public INamedTypeSymbol? StringSyntaxAttribute { get; } + public ImmutableArray StringSyntaxAttributes { get; } public Info? TryGet(IMethodSymbol method, OperationAnalysisContext context) { @@ -369,7 +369,7 @@ public StringFormatInfo(Compilation compilation) return info; } - if (StringSyntaxAttribute is not null && + if (!StringSyntaxAttributes.IsEmpty && TryGetFormatInfoByCompositeFormatStringSyntaxAttribute(method, out info)) { return info; @@ -494,7 +494,7 @@ private int FindParameterIndexOfCompositeFormatStringSyntaxAttribute(ImmutableAr { foreach (AttributeData attribute in parameters[i].GetAttributes()) { - if (StringSyntaxAttribute!.Equals(attribute.AttributeClass, SymbolEqualityComparer.Default)) + if (StringSyntaxAttributes.Contains(attribute.AttributeClass, SymbolEqualityComparer.Default)) { ImmutableArray arguments = attribute.ConstructorArguments; if (arguments.Length == 1 && CompositeFormat.Equals(arguments[0].Value)) diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/UseStringEqualsOverStringCompare.Fixer.cs b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/UseStringEqualsOverStringCompare.Fixer.cs index 487ed4dff99..82efde5079f 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/UseStringEqualsOverStringCompare.Fixer.cs +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/UseStringEqualsOverStringCompare.Fixer.cs @@ -68,7 +68,8 @@ private static ImmutableArray GetOperationReplacers(RequiredS return ImmutableArray.Create( new StringStringCaseReplacer(symbols), new StringStringBoolReplacer(symbols), - new StringStringStringComparisonReplacer(symbols)); + new StringStringStringComparisonReplacer(symbols), + new OrdinalStringStringCaseReplacer(symbols)); } /// @@ -86,7 +87,7 @@ protected OperationReplacer(RequiredSymbols symbols) /// /// Indicates whether the current applies to the specified violation. /// - /// The at the location reported by the analyzer. + /// The or at the location reported by the analyzer. /// True if the current applies to the specified violation. public abstract bool IsMatch(IOperation violation); @@ -94,7 +95,7 @@ protected OperationReplacer(RequiredSymbols symbols) /// Creates a replacement node for a violation that the current applies to. /// Asserts if the current does not apply to the specified violation. /// - /// The obtained at the location reported by the analyzer. + /// The or obtained at the location reported by the analyzer. /// must return for this operation. /// /// @@ -229,5 +230,29 @@ public override SyntaxNode CreateReplacementExpression(IOperation violation, Syn return InvertIfNotEquals(equalsInvocationSyntax, violation, generator); } } + + /// + /// Replaces violations. + /// + private sealed class OrdinalStringStringCaseReplacer : OperationReplacer + { + public OrdinalStringStringCaseReplacer(RequiredSymbols symbols) + : base(symbols) + { } + + public override bool IsMatch(IOperation violation) => UseStringEqualsOverStringCompare.IsOrdinalStringStringCase(violation, Symbols); + + public override SyntaxNode CreateReplacementExpression(IOperation violation, SyntaxGenerator generator) + { + RoslynDebug.Assert(IsMatch(violation)); + + var compareInvocation = GetInvocation(violation); + var equalsInvocationSyntax = generator.InvocationExpression( + CreateEqualsMemberAccess(generator), + compareInvocation.Arguments.GetArgumentsInParameterOrder().Select(x => x.Value.Syntax)); + + return InvertIfNotEquals(equalsInvocationSyntax, violation, generator); + } + } } } diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/UseStringEqualsOverStringCompare.cs b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/UseStringEqualsOverStringCompare.cs index b5e61a8e502..08201fefe93 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/UseStringEqualsOverStringCompare.cs +++ b/src/roslyn-analyzers/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/UseStringEqualsOverStringCompare.cs @@ -79,6 +79,7 @@ private RequiredSymbols( IMethodSymbol? compareStringString, IMethodSymbol? compareStringStringBool, IMethodSymbol? compareStringStringStringComparison, + IMethodSymbol? compareOrdinalStringString, IMethodSymbol? equalsStringString, IMethodSymbol? equalsStringStringStringComparison, IMethodSymbol intEquals) @@ -89,6 +90,7 @@ private RequiredSymbols( CompareStringString = compareStringString; CompareStringStringBool = compareStringStringBool; CompareStringStringStringComparison = compareStringStringStringComparison; + CompareOrdinalStringString = compareOrdinalStringString; EqualsStringString = equalsStringString; EqualsStringStringStringComparison = equalsStringStringStringComparison; IntEquals = intEquals; @@ -115,12 +117,17 @@ public static bool TryGetSymbols(Compilation compilation, [NotNullWhen(true)] ou var compareStringStringBool = compareMethods.GetFirstOrDefaultMemberWithParameterTypes(stringType, stringType, boolType); var compareStringStringStringComparison = compareMethods.GetFirstOrDefaultMemberWithParameterTypes(stringType, stringType, stringComparisonType); + var compareOrdinalMethods = stringType.GetMembers(nameof(string.CompareOrdinal)) + .OfType() + .Where(x => x.IsStatic); + var compareOrdinalStringString = compareOrdinalMethods.GetFirstOrDefaultMemberWithParameterTypes(stringType, stringType); + var equalsMethods = stringType.GetMembers(nameof(string.Equals)) .OfType() .Where(x => x.IsStatic); var equalsStringString = equalsMethods.GetFirstOrDefaultMemberWithParameterTypes(stringType, stringType); var equalsStringStringStringComparison = equalsMethods.GetFirstOrDefaultMemberWithParameterTypes(stringType, stringType, stringComparisonType); - var intType = typeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemInt32); + var intType = compilation.GetSpecialType(SpecialType.System_Int32); var intEquals = intType ?.GetMembers(nameof(int.Equals)) .OfType() @@ -133,14 +140,15 @@ public static bool TryGetSymbols(Compilation compilation, [NotNullWhen(true)] ou // Bail if we do not have at least one complete pair of Compare-Equals methods in the compilation. if ((compareStringString is null || equalsStringString is null) && (compareStringStringBool is null || equalsStringStringStringComparison is null) && - (compareStringStringStringComparison is null || equalsStringStringStringComparison is null)) + (compareStringStringStringComparison is null || equalsStringStringStringComparison is null) && + (compareOrdinalStringString is null || equalsStringString is null)) { return false; } symbols = new RequiredSymbols( stringType, boolType, stringComparisonType, - compareStringString, compareStringStringBool, compareStringStringStringComparison, + compareStringString, compareStringStringBool, compareStringStringStringComparison, compareOrdinalStringString, equalsStringString, equalsStringStringStringComparison, intEquals); return true; } @@ -151,6 +159,7 @@ public static bool TryGetSymbols(Compilation compilation, [NotNullWhen(true)] ou public IMethodSymbol? CompareStringString { get; } public IMethodSymbol? CompareStringStringBool { get; } public IMethodSymbol? CompareStringStringStringComparison { get; } + public IMethodSymbol? CompareOrdinalStringString { get; } public IMethodSymbol? EqualsStringString { get; } public IMethodSymbol? EqualsStringStringStringComparison { get; } public IMethodSymbol IntEquals { get; } @@ -291,10 +300,39 @@ internal static bool IsStringStringStringComparisonCase(IOperation operation, Re invocation.TargetMethod.Equals(symbols.CompareStringStringStringComparison, SymbolEqualityComparer.Default); } + /// + /// Returns true if the specified is an or : + /// + /// Is an equals or not-equals operation + /// One operand is a literal zero + /// The other operand is any invocation of + /// + /// + /// The operation to check + /// The cache of symbols to be used for checking against known symbols. + /// true if the is one of the matching symbols. + internal static bool IsOrdinalStringStringCase(IOperation operation, RequiredSymbols symbols) + { + // Don't report a diagnostic if either the string.CompareOrdinal overload or the + // corresponding string.Equals overload is missing. + if (symbols.CompareOrdinalStringString is null || + symbols.EqualsStringString is null) + { + return false; + } + + var invocation = GetInvocationFromEqualityCheckWithLiteralZero(operation as IBinaryOperation) + ?? GetInvocationFromEqualsCheckWithLiteralZero(operation as IInvocationOperation, symbols.IntEquals); + + return invocation is not null && + invocation.TargetMethod.Equals(symbols.CompareOrdinalStringString, SymbolEqualityComparer.Default); + } + private static readonly ImmutableArray> CaseSelectors = ImmutableArray.Create>( IsStringStringCase, IsStringStringBoolCase, - IsStringStringStringComparisonCase); + IsStringStringStringComparisonCase, + IsOrdinalStringStringCase); } } diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.md b/src/roslyn-analyzers/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.md index a9f675abf06..6bf23d03e24 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.md +++ b/src/roslyn-analyzers/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.md @@ -2130,6 +2130,18 @@ The property 'StreamReader.EndOfStream' can cause unintended synchronous blockin |CodeFix|False| --- +## [CA2025](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2025): Do not pass 'IDisposable' instances into unawaited tasks + +Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed. + +|Item|Value| +|-|-| +|Category|Reliability| +|Enabled|True| +|Severity|Warning| +|CodeFix|False| +--- + ## [CA2100](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2100): Review SQL queries for security vulnerabilities SQL queries that directly use user input can be vulnerable to SQL injection attacks. Review this SQL query for potential vulnerabilities, and consider using a parameterized SQL query. diff --git a/src/roslyn-analyzers/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.sarif b/src/roslyn-analyzers/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.sarif index a46fddbcd23..219d9297d6a 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.sarif +++ b/src/roslyn-analyzers/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.sarif @@ -3811,6 +3811,26 @@ ] } }, + "CA2025": { + "id": "CA2025", + "shortDescription": "Do not pass 'IDisposable' instances into unawaited tasks", + "fullDescription": "Unawaited tasks that use 'IDisposable' instances may use those instances long after they have been disposed. Ensure tasks using those instances are completed before the instances are disposed.", + "defaultLevel": "warning", + "helpUri": "https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2025", + "properties": { + "category": "Reliability", + "isEnabledByDefault": true, + "typeName": "DoNotPassDisposablesIntoUnawaitedTasksAnalyzer", + "languages": [ + "C#", + "Visual Basic" + ], + "tags": [ + "Telemetry", + "EnabledRuleInAggressiveMode" + ] + } + }, "CA2100": { "id": "CA2100", "shortDescription": "Review SQL queries for security vulnerabilities", diff --git a/src/roslyn-analyzers/src/NetAnalyzers/RulesMissingDocumentation.md b/src/roslyn-analyzers/src/NetAnalyzers/RulesMissingDocumentation.md index c5820fde91a..ebb67482011 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/RulesMissingDocumentation.md +++ b/src/roslyn-analyzers/src/NetAnalyzers/RulesMissingDocumentation.md @@ -6,3 +6,4 @@ CA1873 | | Use 'Regex.IsMatch' | CA1875 | | Use 'Regex.Count' | CA2023 | | Invalid braces in message template | +CA2025 | | Do not pass 'IDisposable' instances into unawaited tasks | diff --git a/src/roslyn-analyzers/src/NetAnalyzers/UnitTests/Microsoft.CodeQuality.Analyzers/QualityGuidelines/DoNotPassDisposablesIntoUnawaitedTasksTests.cs b/src/roslyn-analyzers/src/NetAnalyzers/UnitTests/Microsoft.CodeQuality.Analyzers/QualityGuidelines/DoNotPassDisposablesIntoUnawaitedTasksTests.cs new file mode 100644 index 00000000000..e511ca5b386 --- /dev/null +++ b/src/roslyn-analyzers/src/NetAnalyzers/UnitTests/Microsoft.CodeQuality.Analyzers/QualityGuidelines/DoNotPassDisposablesIntoUnawaitedTasksTests.cs @@ -0,0 +1,736 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Threading.Tasks; +using Xunit; +using VerifyCS = Test.Utilities.CSharpCodeFixVerifier< + Microsoft.CodeQuality.Analyzers.QualityGuidelines.DoNotPassDisposablesIntoUnawaitedTasksAnalyzer, + Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>; +using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier< + Microsoft.CodeQuality.Analyzers.QualityGuidelines.DoNotPassDisposablesIntoUnawaitedTasksAnalyzer, + Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>; + +namespace Microsoft.CodeQuality.Analyzers.QualityGuidelines.UnitTests +{ + public class DoNotPassDisposablesIntoUnawaitedTasksTests + { + #region Diagnostic + + [Fact] + public async Task UsingBlockNoConversion_DiagnosticAsync() + { + await VerifyCS.VerifyAnalyzerAsync(@" +using System.IO; +using System.Threading.Tasks; + +public class C +{ + public static async Task D() + { + using (var ms = new MemoryStream()) + { + var res = DoAsync({|CA2025:ms|}); + } + } + + public static Task DoAsync(MemoryStream s) => Task.FromResult(string.Empty); +} +"); + + await VerifyVB.VerifyAnalyzerAsync(@" +Imports System.IO +Imports System.Threading.Tasks + +Public Class C + Public Shared Async Function D() As Task + Using ms = New MemoryStream() + Dim res = DoAsync({|CA2025:ms|}) + End Using + End Function + + Public Shared Function DoAsync(ByVal s As MemoryStream) As Task(Of String) + Return Task.FromResult(String.Empty) + End Function +End Class +"); + } + + [Fact] + public async Task UsingBlockWithConversion_DiagnosticAsync() + { + // Conversion from MemoryStream to Stream + await VerifyCS.VerifyAnalyzerAsync(@" +using System.IO; +using System.Threading.Tasks; + +public class C +{ + public static async Task D() + { + using (var ms = new MemoryStream()) + { + var res = DoAsync({|CA2025:ms|}); + } + } + + public static Task DoAsync(Stream s) => Task.FromResult(string.Empty); +} +"); + + await VerifyVB.VerifyAnalyzerAsync(@" +Imports System.IO +Imports System.Threading.Tasks + +Public Class C + Public Shared Async Function D() As Task + Using ms = New MemoryStream() + Dim res = DoAsync({|CA2025:ms|}) + End Using + End Function + + Public Shared Function DoAsync(ByVal s As Stream) As Task(Of String) + Return Task.FromResult(String.Empty) + End Function +End Class +"); + } + + [Fact] + public async Task MultipleDisposables_DiagnosticAsync() + { + await VerifyCS.VerifyAnalyzerAsync(@" +using System.IO; +using System.Threading.Tasks; + +public class C +{ + public static Task D() + { + var ms = new MemoryStream(); + var reader = new StreamReader(ms); + Task doStuff = DoAsync({|CA2025:ms|}, {|CA2025:reader|}); + ms.Dispose(); + reader.Dispose(); + return doStuff; + } + + public static Task DoAsync(Stream s, StreamReader r) => Task.FromResult(string.Empty); +} +"); + + await VerifyVB.VerifyAnalyzerAsync(@" +Imports System.IO +Imports System.Threading.Tasks + +Public Class C + Public Shared Function D() As Task + Dim ms = New MemoryStream() + Dim reader = New StreamReader(ms) + Dim doStuff As Task(Of String) = DoAsync({|CA2025:ms|}, {|CA2025:reader|}) + ms.Dispose() + reader.Dispose() + Return doStuff + End Function + + Public Shared Function DoAsync(ByVal s As Stream, ByVal r As StreamReader) As Task(Of String) + Return Task.FromResult(String.Empty) + End Function +End Class +"); + } + + [Fact] + public async Task MultipleCallsWithSameDisposable_DiagnosticAsync() + { + await VerifyCS.VerifyAnalyzerAsync(@" +using System.IO; +using System.Threading.Tasks; + +public class C +{ + public static async Task D() + { + using (var ms = new MemoryStream()) + { + var res = DoAsync({|CA2025:ms|}); + var res1 = DoAsync({|CA2025:ms|}); + await DoAsync(ms); + } + } + + public static Task DoAsync(MemoryStream s) => Task.FromResult(string.Empty); +} +"); + + await VerifyVB.VerifyAnalyzerAsync(@" +Imports System.IO +Imports System.Threading.Tasks + +Public Class C + Public Shared Async Function D() As Task + Using ms = New MemoryStream() + Dim res = DoAsync({|CA2025:ms|}) + Dim res1 = DoAsync({|CA2025:ms|}) + Await DoAsync(ms) + End Using + End Function + + Public Shared Function DoAsync(ByVal s As MemoryStream) As Task(Of String) + Return Task.FromResult(String.Empty) + End Function +End Class +"); + } + + [Fact] + public async Task SimpleUsingStatement_DiagnosticAsync() + { + await new VerifyCS.Test + { + TestCode = @" +using System.IO; +using System.Threading.Tasks; + +public class C +{ + public static async Task D() + { + using var ms = new MemoryStream(); + var res = DoAsync(ms); + } + + public static Task DoAsync(MemoryStream s) => Task.FromResult(string.Empty); +}", + LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp8, + ExpectedDiagnostics = + { + VerifyCS.Diagnostic().WithSpan(10, 27, 10, 29) + } + }.RunAsync(); + } + + [Fact] + public async Task AwaitedAfterwardsButDisposedBeforeAwait_DiagnosticAsync() + { + await VerifyCS.VerifyAnalyzerAsync(@" +using System.IO; +using System.Threading.Tasks; + +public class C +{ + public static async Task D() + { + var ms = new MemoryStream(); + var t = DoAsync({|CA2025:ms|}); + ms.Dispose(); + await t.ConfigureAwait(false); + } + + public static Task DoAsync(Stream s) => Task.CompletedTask; +} +"); + } + + [Fact] + public async Task ReturnFromMethod_DiagnosticAsync() + { + await VerifyCS.VerifyAnalyzerAsync(@" +using System.IO; +using System.Threading.Tasks; + +public class C +{ + public static Task D() + { + using (var ms = new MemoryStream()) + { + return DoAsync({|CA2025:ms|}); + } + } + + public static Task DoAsync(Stream s) => Task.FromResult(string.Empty); +} +"); + + await VerifyVB.VerifyAnalyzerAsync(@" +Imports System.IO +Imports System.Threading.Tasks + +Public Class C + Public Shared Function D() As Task + Using ms = New MemoryStream() + Return DoAsync({|CA2025:ms|}) + End Using + End Function + + Public Shared Function DoAsync(ByVal s As Stream) As Task(Of String) + Return Task.FromResult(String.Empty) + End Function +End Class +"); + } + + [Fact] + public async Task NestedUsingStatements_DiagnosticAsync() + { + await VerifyCS.VerifyAnalyzerAsync(@" +using System.IO; +using System.Threading.Tasks; + +public class C +{ + public static Task D() + { + using (var ms = new MemoryStream()) + { + using (var reader = new StreamReader(ms)) + { + return DoAsync({|CA2025:ms|}, {|CA2025:reader|}); + } + } + } + + public static Task DoAsync(Stream s, StreamReader r) => Task.FromResult(string.Empty); +} +"); + + await VerifyVB.VerifyAnalyzerAsync(@" +Imports System.IO +Imports System.Threading.Tasks + +Public Class C + Public Shared Function D() As Task + Using ms = New MemoryStream() + + Using reader = New StreamReader(ms) + Return DoAsync({|CA2025:ms|}, {|CA2025:reader|}) + End Using + End Using + End Function + + Public Shared Function DoAsync(ByVal s As Stream, ByVal r As StreamReader) As Task(Of String) + Return Task.FromResult(String.Empty) + End Function +End Class +"); + } + + [Fact] + public async Task ManualDisposeWithTryFinally_DiagnosticAsync() + { + await VerifyCS.VerifyAnalyzerAsync(@" +using System.IO; +using System.Threading.Tasks; + +public class C +{ + public static async Task D() + { + var ms = new MemoryStream(); + try + { + var res = DoAsync({|CA2025:ms|}); + } + finally + { + ms.Dispose(); + } + } + + public static Task DoAsync(MemoryStream s) => Task.FromResult(string.Empty); +} +"); + + await VerifyVB.VerifyAnalyzerAsync(@" +Imports System.IO +Imports System.Threading.Tasks + +Public Class C + Public Shared Async Function D() As Task + Dim ms = New MemoryStream() + + Try + Dim res = DoAsync({|CA2025:ms|}) + Finally + ms.Dispose() + End Try + End Function + + Public Shared Function DoAsync(ByVal s As MemoryStream) As Task(Of String) + Return Task.FromResult(String.Empty) + End Function +End Class +"); + } + + [Fact] + public async Task ManualDisposeWithTask_DiagnosticAsync() + { + await VerifyCS.VerifyAnalyzerAsync(@" +using System.IO; +using System.Threading.Tasks; + +public class C +{ + public static Task D() + { + var ms = new MemoryStream(); + Task doStuff = DoAsync({|CA2025:ms|}); + ms.Dispose(); + return doStuff; + } + + public static Task DoAsync(Stream s) => Task.CompletedTask; +} +"); + + await VerifyVB.VerifyAnalyzerAsync(@" +Imports System.IO +Imports System.Threading.Tasks + +Public Class C + Public Shared Function D() As Task + Dim ms = New MemoryStream() + Dim doStuff As Task = DoAsync({|CA2025:ms|}) + ms.Dispose() + Return doStuff + End Function + + Public Shared Function DoAsync(ByVal s As Stream) As Task + Return Task.CompletedTask + End Function +End Class +"); + } + + [Fact] + public async Task ManualDisposeWithTaskString_DiagnosticAsync() + { + await VerifyCS.VerifyAnalyzerAsync(@" +using System.IO; +using System.Threading.Tasks; + +public class C +{ + public static Task D() + { + var ms = new MemoryStream(); + Task doStuff = DoAsync({|CA2025:ms|}); + ms.Dispose(); + return doStuff; + } + + public static Task DoAsync(Stream s) => Task.FromResult(string.Empty); +} +"); + + await VerifyVB.VerifyAnalyzerAsync(@" +Imports System.IO +Imports System.Threading.Tasks + +Public Class C + Public Shared Function D() As Task + Dim ms = New MemoryStream() + Dim doStuff As Task(Of String) = DoAsync({|CA2025:ms|}) + ms.Dispose() + Return doStuff + End Function + + Public Shared Function DoAsync(ByVal s As Stream) As Task(Of String) + Return Task.FromResult(String.Empty) + End Function +End Class +"); + } + + #endregion Diagnostic + + #region No Diagnostic + + [Fact] + public async Task AwaitedTask_NoDiagnosticAsync() + { + await VerifyCS.VerifyAnalyzerAsync(@" +using System.IO; +using System.Threading.Tasks; + +public class C +{ + public static async Task D() + { + var ms = new MemoryStream(); + var res = await DoAsync(ms); + ms.Dispose(); + } + + public static Task DoAsync(Stream s) => Task.FromResult(string.Empty); +} +"); + + await VerifyVB.VerifyAnalyzerAsync(@" +Imports System.IO +Imports System.Threading.Tasks + +Public Class C + Public Shared Async Function D() As Task + Dim ms = New MemoryStream() + Dim res = Await DoAsync(ms) + ms.Dispose() + End Function + + Public Shared Function DoAsync(ByVal s As Stream) As Task(Of String) + Return Task.FromResult(String.Empty) + End Function +End Class +"); + } + + [Fact] + public async Task UnawaitedWithNoDispose_NoDiagnosticAsync() + { + await VerifyCS.VerifyAnalyzerAsync(@" +using System.IO; +using System.Threading.Tasks; + +public class C +{ + public static Task D() + { + var ms = new MemoryStream(); + Task doStuff = DoAsync(ms); + return doStuff; + } + + public static Task DoAsync(Stream s) => Task.FromResult(string.Empty); +} +"); + + await VerifyVB.VerifyAnalyzerAsync(@" +Imports System.IO +Imports System.Threading.Tasks + +Public Class C + Public Shared Function D() As Task + Dim ms = New MemoryStream() + Dim doStuff As Task(Of String) = DoAsync(ms) + Return doStuff + End Function + + Public Shared Function DoAsync(ByVal s As Stream) As Task(Of String) + Return Task.FromResult(String.Empty) + End Function +End Class +"); + } + + [Fact] + public async Task TaskWaitedSynchronously_NoDiagnosticAsync() + { + await VerifyCS.VerifyAnalyzerAsync(@" +using System.IO; +using System.Threading.Tasks; + +public class C +{ + public static void D() + { + var ms = new MemoryStream(); + DoAsync(ms).Wait(); + ms.Dispose(); + } + + public static Task DoAsync(Stream s) => Task.CompletedTask; +} +"); + + await VerifyVB.VerifyAnalyzerAsync(@" +Imports System.IO +Imports System.Threading.Tasks + +Public Class C + Public Shared Sub D() + Dim ms = New MemoryStream() + DoAsync(ms).Wait() + ms.Dispose() + End Sub + + Public Shared Function DoAsync(ByVal s As Stream) As Task + Return Task.CompletedTask + End Function +End Class +"); + } + + [Fact] + public async Task TaskResultReceivedSynchronously_NoDiagnosticAsync() + { + await VerifyCS.VerifyAnalyzerAsync(@" +using System.IO; +using System.Threading.Tasks; + +public class C +{ + public static void D() + { + var ms = new MemoryStream(); + var res = DoAsync(ms).Result; + ms.Dispose(); + } + + public static Task DoAsync(Stream s) => Task.FromResult(string.Empty); +} +"); + + await VerifyVB.VerifyAnalyzerAsync(@" +Imports System.IO +Imports System.Threading.Tasks + +Public Class C + Public Shared Sub D() + Dim ms = New MemoryStream() + Dim res = DoAsync(ms).Result + ms.Dispose() + End Sub + + Public Shared Function DoAsync(ByVal s As Stream) As Task(Of String) + Return Task.FromResult(String.Empty) + End Function +End Class +"); + } + + [Fact] + public async Task AwaitedElsewhereBeforeDispose_NoDiagnosticAsync() + { + await VerifyCS.VerifyAnalyzerAsync(@" +using System.IO; +using System.Threading.Tasks; + +public class C +{ + public static async Task D() + { + var ms = new MemoryStream(); + var t = DoAsync(ms); + var val = ms.Length - ms.Position; + await t; + + ms.Dispose(); + } + + public static Task DoAsync(Stream s) => Task.CompletedTask; +} +"); + + await VerifyVB.VerifyAnalyzerAsync(@" +Imports System.IO +Imports System.Threading.Tasks + +Public Class C + Public Shared Async Function D() As Task + Dim ms = New MemoryStream() + Dim t = DoAsync(ms) + Dim val = ms.Length - ms.Position + Await t + ms.Dispose() + End Function + + Public Shared Function DoAsync(ByVal s As Stream) As Task + Return Task.CompletedTask + End Function +End Class +"); + } + + [Fact] + public async Task AwaitedElsewhereBeforeDisposeMultipleArgs_NoDiagnosticAsync() + { + await VerifyCS.VerifyAnalyzerAsync(@" +using System.IO; +using System.Threading.Tasks; + +public class C +{ + public static async Task D() + { + var ms = new MemoryStream(); + var reader = new StreamReader(ms); + + var t = DoAsync(ms, reader); + var val = ms.Length - ms.Position; + await t; + + ms.Dispose(); + } + + public static Task DoAsync(Stream s, StreamReader r) => Task.CompletedTask; +} +"); + + await VerifyVB.VerifyAnalyzerAsync(@" +Imports System.IO +Imports System.Threading.Tasks + +Public Class C + Public Shared Async Function D() As Task + Dim ms = New MemoryStream() + Dim reader = New StreamReader(ms) + Dim t = DoAsync(ms, reader) + Dim val = ms.Length - ms.Position + Await t + ms.Dispose() + End Function + + Public Shared Function DoAsync(ByVal s As Stream, ByVal r As StreamReader) As Task + Return Task.CompletedTask + End Function +End Class +"); + } + + [Fact] + public async Task AwaitedElsewhereBeforeDisposeConfigureAwait_NoDiagnosticAsync() + { + // Ensures we register the await even when it's not the direct parent of the local invocation + await VerifyCS.VerifyAnalyzerAsync(@" +using System.IO; +using System.Threading.Tasks; + +public class C +{ + public static async Task D() + { + var ms = new MemoryStream(); + var t = DoAsync(ms); + var val = ms.Length - ms.Position; + await t.ConfigureAwait(false); + + ms.Dispose(); + } + + public static Task DoAsync(Stream s) => Task.CompletedTask; +} +"); + + await VerifyVB.VerifyAnalyzerAsync(@" +Imports System.IO +Imports System.Threading.Tasks + +Public Class C + Public Shared Async Function D() As Task + Dim ms = New MemoryStream() + Dim t = DoAsync(ms) + Dim val = ms.Length - ms.Position + Await t.ConfigureAwait(False) + ms.Dispose() + End Function + + Public Shared Function DoAsync(ByVal s As Stream) As Task + Return Task.CompletedTask + End Function +End Class +"); + } + + #endregion No Diagnostic + } +} \ No newline at end of file diff --git a/src/roslyn-analyzers/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/DoNotCallEnumerableCastOrOfTypeWithIncompatibleTypesAnalyzerTests.cs b/src/roslyn-analyzers/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/DoNotCallEnumerableCastOrOfTypeWithIncompatibleTypesAnalyzerTests.cs index 7e6523ce82e..9ee0cd68ad2 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/DoNotCallEnumerableCastOrOfTypeWithIncompatibleTypesAnalyzerTests.cs +++ b/src/roslyn-analyzers/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/DoNotCallEnumerableCastOrOfTypeWithIncompatibleTypesAnalyzerTests.cs @@ -910,6 +910,82 @@ class GenericDerived : GenericBase await test.RunAsync(); } + [Fact, WorkItem(7031, "https://github.com/dotnet/roslyn-analyzers/issues/7031")] + public async Task GenericConstraints() + { + // ensure runtime behavior is matches + _ = new Enum[] { StringComparison.OrdinalIgnoreCase }.Cast().ToArray(); + _ = new ValueType[] { int.MaxValue }.Cast().ToArray(); + + var test = new VerifyCS.Test + { + ReferenceAssemblies = ReferenceAssemblies.Net.Net90, + LanguageVersion = LanguageVersion.Latest, + + TestCode = @" +using System; +using System.Collections.Generic; +using System.Linq; + +public static class Program +{ + public static IEnumerable CastFromEnums(IEnumerable values) where T : struct, Enum + => values.Cast(); + + public static IEnumerable CastFromValueTypes(IEnumerable values) where T : struct + => values.Cast(); + + public static IEnumerable CastToEnums(IEnumerable values) where T : struct, Enum + => values.Cast(); + + public static IEnumerable CastToValueTypes(IEnumerable values) where T : struct + => values.Cast(); + + public static IEnumerable CastValueTypes(IEnumerable values) where T : struct + => values.Cast(); + + public static IEnumerable CastUnconstrainedGeneric(IEnumerable values) + => values.Cast(); + + public static IEnumerable CastGenericUnmanagedToGeneric(IEnumerable values) + where TOut : unmanaged + => values.Cast(); + + public static IEnumerable CastGenericUnmanagedToGenericUnmanagedl(IEnumerable values) + where TIn : unmanaged + where TOut : unmanaged + => values.Cast(); + + public static IEnumerable CastGenericNotNullToGenericNotNull(IEnumerable values) + where TIn : notnull + where TOut : notnull + => values.Cast(); + + public static IEnumerable CastGenericToGeneric(IEnumerable values) + where TIn : Enum + where TOut : Uri + => {|#1:values.Cast()|}; + + public static IEnumerable CastGenericStructToGeneric(IEnumerable values) + where TIn : struct + where TOut : Uri + => {|#2:values.Cast()|}; + + public static IEnumerable CastGenericToGenericStruct(IEnumerable values) + where TIn : Uri + where TOut : struct + => {|#3:values.Cast()|}; +}", + ExpectedDiagnostics = + { + VerifyCS.Diagnostic(castRule).WithLocation(1).WithArguments("TIn", "TOut"), + VerifyCS.Diagnostic(castRule).WithLocation(2).WithArguments("TIn", "TOut"), + VerifyCS.Diagnostic(castRule).WithLocation(3).WithArguments("TIn", "TOut"), + } + }; + await test.RunAsync(); + } + [Fact] public async Task NonGenericCasesVB() { diff --git a/src/roslyn-analyzers/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethodsTests.cs b/src/roslyn-analyzers/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethodsTests.cs index 798bfcf45fc..1b48e8b2fc2 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethodsTests.cs +++ b/src/roslyn-analyzers/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/ProvideCorrectArgumentsToFormattingMethodsTests.cs @@ -678,6 +678,154 @@ End Class" await basicTest.RunAsync(); } + [Fact] + public async Task EditorConfigConfiguration_StringSyntaxAnnotatedMethodsMultipleFrameworksAsync() + { + await new VerifyCS.Test + { + TestState = + { + Sources = + { + """ + using System.Diagnostics.CodeAnalysis; + + class Test + { + public static string MyFormat([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string specification, params object[] args) => specification; + + void M1(string param) + { + var a = [|MyFormat("", 1)|]; + var b = [|NetStandardTest.MyFormat("", 1)|]; + } + } + """ + }, + AdditionalProjects = + { + ["NetstandardReference"] = + { + ReferenceAssemblies = ReferenceAssemblies.NetStandard.NetStandard20, + Sources = + { + """ + using System.Diagnostics.CodeAnalysis; + + public class NetStandardTest + { + public static string MyFormat([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string specification, params object[] args) => specification; + } + """, + """ + namespace System.Diagnostics.CodeAnalysis + { + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] + internal sealed class StringSyntaxAttribute : Attribute + { + public StringSyntaxAttribute(string syntax) + { + Syntax = syntax; + Arguments = Array.Empty(); + } + + public StringSyntaxAttribute(string syntax, params object?[] arguments) + { + Syntax = syntax; + Arguments = arguments; + } + + public string Syntax { get; } + public object?[] Arguments { get; } + public const string CompositeFormat = nameof(CompositeFormat); + } + } + """ + }, + } + }, + AdditionalProjectReferences = + { + "NetstandardReference" + }, + ReferenceAssemblies = ReferenceAssemblies.Net.Net70, + }, + MarkupOptions = MarkupOptions.UseFirstDescriptor, + }.RunAsync(); + + await new VerifyVB.Test + { + TestState = + { + Sources = + { + """ + Imports System.Diagnostics.CodeAnalysis + + Class Test + Public Shared Function MyFormat( specification As String, ParamArray args As Object()) As String + Return specification + End Function + + Private Sub M1(ByVal param As String) + Dim a = [|MyFormat("", 1)|] + Dim b = [|NetStandardTest.MyFormat("", 1)|] + End Sub + End Class + """ + }, + AdditionalProjects = + { + ["NetstandardReference", LanguageNames.CSharp] = + { + ReferenceAssemblies = ReferenceAssemblies.NetStandard.NetStandard20, + Sources = + { + """ + using System.Diagnostics.CodeAnalysis; + + public class NetStandardTest + { + public static string MyFormat([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string specification, params object[] args) => specification; + } + """, + """ + namespace System.Diagnostics.CodeAnalysis + { + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] + internal sealed class StringSyntaxAttribute : Attribute + { + public StringSyntaxAttribute(string syntax) + { + Syntax = syntax; + Arguments = Array.Empty(); + } + + public StringSyntaxAttribute(string syntax, params object?[] arguments) + { + Syntax = syntax; + Arguments = arguments; + } + + public string Syntax { get; } + public object?[] Arguments { get; } + public const string CompositeFormat = nameof(CompositeFormat); + } + } + """ + }, + } + }, + AdditionalProjectReferences = + { + "NetstandardReference" + }, + ReferenceAssemblies = ReferenceAssemblies.Net.Net70, + }, + MarkupOptions = MarkupOptions.UseFirstDescriptor, + }.RunAsync(); + } + [Fact] [WorkItem(90357, "https://github.com/dotnet/runtime/issues/90357")] public async Task CA2241CSharpMethodWithNoPossibleArgumentsOnlyChecksFormat() diff --git a/src/roslyn-analyzers/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/UseStringEqualsOverStringCompareTests.cs b/src/roslyn-analyzers/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/UseStringEqualsOverStringCompareTests.cs index 33097d79621..0a5a603465c 100644 --- a/src/roslyn-analyzers/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/UseStringEqualsOverStringCompareTests.cs +++ b/src/roslyn-analyzers/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/UseStringEqualsOverStringCompareTests.cs @@ -29,6 +29,7 @@ private static readonly (string CompareCall, string EqualsCall)[] CS_ComparisonE ("string.Compare(x, y, StringComparison.CurrentCulture)", "string.Equals(x, y, StringComparison.CurrentCulture)"), ("string.Compare(x, y, StringComparison.Ordinal)", "string.Equals(x, y, StringComparison.Ordinal)"), ("string.Compare(x, y, StringComparison.OrdinalIgnoreCase)", "string.Equals(x, y, StringComparison.OrdinalIgnoreCase)"), + ("string.CompareOrdinal(x, y)", "string.Equals(x, y)"), }; private static readonly (string CompareCall, string EqualsCall)[] VB_ComparisonEqualityMethodPairs = new[] @@ -39,6 +40,7 @@ private static readonly (string CompareCall, string EqualsCall)[] VB_ComparisonE ("String.Compare(x, y, StringComparison.CurrentCulture)", "String.Equals(x, y, StringComparison.CurrentCulture)"), ("String.Compare(x, y, StringComparison.Ordinal)", "String.Equals(x, y, StringComparison.Ordinal)"), ("String.Compare(x, y, StringComparison.OrdinalIgnoreCase)", "String.Equals(x, y, StringComparison.OrdinalIgnoreCase)"), + ("String.CompareOrdinal(x, y)", "String.Equals(x, y)"), }; public static IEnumerable CS_ComparisonLeftOfLiteralTestData { get; } = CS_ComparisonEqualityMethodCallPairs @@ -83,6 +85,7 @@ public static IEnumerable CS_IneligibleStringCompareOverloadTestData { yield return new[] { "string.Compare(x, y, true, System.Globalization.CultureInfo.InvariantCulture)" }; yield return new[] { "string.Compare(x, y, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.CompareOptions.None)" }; + yield return new[] { "string.CompareOrdinal(x, indexA: 0, y, indexB: 0, length: 0)" }; } } @@ -92,6 +95,7 @@ public static IEnumerable VB_IneligibleStringCompareOverloadTestData { yield return new[] { "String.Compare(x, y, true, System.Globalization.CultureInfo.InvariantCulture)" }; yield return new[] { "String.Compare(x, y, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.CompareOptions.None)" }; + yield return new[] { "String.CompareOrdinal(x, indexA:= 0, y, indexB:= 0, length:= 0)" }; } } diff --git a/src/roslyn-analyzers/src/Utilities/Compiler/Analyzer.Utilities.projitems b/src/roslyn-analyzers/src/Utilities/Compiler/Analyzer.Utilities.projitems index 73bf50bd0dc..2116dbc921b 100644 --- a/src/roslyn-analyzers/src/Utilities/Compiler/Analyzer.Utilities.projitems +++ b/src/roslyn-analyzers/src/Utilities/Compiler/Analyzer.Utilities.projitems @@ -43,6 +43,8 @@ + + @@ -119,6 +121,7 @@ + diff --git a/src/roslyn-analyzers/src/Utilities/Compiler/CachingBase`1.cs b/src/roslyn-analyzers/src/Utilities/Compiler/CachingBase`1.cs new file mode 100644 index 00000000000..37bdb071218 --- /dev/null +++ b/src/roslyn-analyzers/src/Utilities/Compiler/CachingBase`1.cs @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Diagnostics; + +namespace Analyzer.Utilities +{ + internal abstract class CachingBase + { + private readonly int _alignedSize; + private TEntry[]? _entries; + + // cache size is always ^2. + // items are placed at [hash ^ mask] + // new item will displace previous one at the same location. + protected readonly int mask; + + // See docs for createBackingArray on the constructor for why using the non-threadsafe ??= is ok here. + protected TEntry[] Entries => _entries ??= new TEntry[_alignedSize]; + + /// Whether or not the backing array should be created immediately, or should + /// be deferred until the first time that is used. Note: if is then the array will be created in a non-threadsafe + /// fashion (effectively different threads might observe a small window of time when different arrays could be + /// returned. Derived types should only pass here if that behavior is acceptable for + /// their use case. + internal CachingBase(int size, bool createBackingArray = true) + { + _alignedSize = AlignSize(size); + this.mask = _alignedSize - 1; + _entries = createBackingArray ? new TEntry[_alignedSize] : null; + } + + private static int AlignSize(int size) + { + Debug.Assert(size > 0); + + size--; + size |= size >> 1; + size |= size >> 2; + size |= size >> 4; + size |= size >> 8; + size |= size >> 16; + return size + 1; + } + } +} diff --git a/src/roslyn-analyzers/src/Utilities/Compiler/ConcurrentCache`2.cs b/src/roslyn-analyzers/src/Utilities/Compiler/ConcurrentCache`2.cs new file mode 100644 index 00000000000..b8f85a737f7 --- /dev/null +++ b/src/roslyn-analyzers/src/Utilities/Compiler/ConcurrentCache`2.cs @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +namespace Analyzer.Utilities +{ + // very simple cache with a specified size. + // expiration policy is "new entry wins over old entry if hashed into the same bucket" + internal sealed class ConcurrentCache : CachingBase.Entry> + where TKey : notnull + { + private readonly IEqualityComparer _keyComparer; + + // class, to ensure atomic updates. + internal class Entry + { + internal readonly int hash; + internal readonly TKey key; + internal readonly TValue value; + + internal Entry(int hash, TKey key, TValue value) + { + this.hash = hash; + this.key = key; + this.value = value; + } + } + + public ConcurrentCache(int size, IEqualityComparer keyComparer) + // Defer creating the backing array until it is actually needed. This saves on expensive allocations for + // short-lived compilations that do not end up using the cache. As the cache is simple best-effort, it's + // fine if multiple threads end up creating the backing array at the same time. One thread will be last and + // will win, and the others will just end up creating a small piece of garbage that will be collected. + : base(size, createBackingArray: false) + { + _keyComparer = keyComparer; + } + + public ConcurrentCache(int size) + : this(size, EqualityComparer.Default) { } + + public bool TryAdd(TKey key, TValue value) + { + var hash = _keyComparer.GetHashCode(key); + var idx = hash & mask; + + var entry = this.Entries[idx]; + if (entry != null && entry.hash == hash && _keyComparer.Equals(entry.key, key)) + { + return false; + } + + Entries[idx] = new Entry(hash, key, value); + return true; + } + + public bool TryGetValue(TKey key, [MaybeNullWhen(returnValue: false)] out TValue value) + { + int hash = _keyComparer.GetHashCode(key); + int idx = hash & mask; + + var entry = this.Entries[idx]; + if (entry != null && entry.hash == hash && _keyComparer.Equals(entry.key, key)) + { + value = entry.value; + return true; + } + + value = default!; + return false; + } + } +} diff --git a/src/roslyn-analyzers/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt b/src/roslyn-analyzers/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt index c97e0bab9fe..84d171e834b 100644 --- a/src/roslyn-analyzers/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt +++ b/src/roslyn-analyzers/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt @@ -18,7 +18,7 @@ Usage: CA1801, CA1806, CA1816, CA2200-CA2209, CA2211-CA2265 Naming: CA1700-CA1727 Interoperability: CA1400-CA1422 Maintainability: CA1500-CA1515 -Reliability: CA9998-CA9999, CA2000-CA2024 +Reliability: CA9998-CA9999, CA2000-CA2025 Documentation: CA1200-CA1200 # Microsoft CodeAnalysis API rules diff --git a/src/roslyn-analyzers/src/Utilities/Compiler/Extensions/CompilationExtensions.cs b/src/roslyn-analyzers/src/Utilities/Compiler/Extensions/CompilationExtensions.cs index 388e17b8e92..0f41db3d184 100644 --- a/src/roslyn-analyzers/src/Utilities/Compiler/Extensions/CompilationExtensions.cs +++ b/src/roslyn-analyzers/src/Utilities/Compiler/Extensions/CompilationExtensions.cs @@ -2,11 +2,11 @@ #if CODEANALYSIS_V3_OR_BETTER using System; -using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.Diagnostics; #endif +using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis; @@ -49,6 +49,9 @@ internal static bool IsWebProject(this Compilation compilation, AnalyzerOptions } #endif + public static ImmutableArray GetTypesByMetadataName(this Compilation compilation, string fullyQualifiedMetadataName) + => WellKnownTypeProvider.GetOrCreate(compilation).GetTypesByMetadataName(fullyQualifiedMetadataName); + /// /// Gets a type by its full type name and cache it at the compilation level. /// diff --git a/src/roslyn-analyzers/src/Utilities/Compiler/ReferenceEqualityComparer.cs b/src/roslyn-analyzers/src/Utilities/Compiler/ReferenceEqualityComparer.cs new file mode 100644 index 00000000000..279b5e8b4da --- /dev/null +++ b/src/roslyn-analyzers/src/Utilities/Compiler/ReferenceEqualityComparer.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace Analyzer.Utilities +{ + /// + /// Compares objects based upon their reference identity. + /// + internal class ReferenceEqualityComparer : IEqualityComparer + { + public static readonly ReferenceEqualityComparer Instance = new(); + + private ReferenceEqualityComparer() + { + } + + bool IEqualityComparer.Equals(object? a, object? b) + { + return a == b; + } + + int IEqualityComparer.GetHashCode(object? a) + { + return ReferenceEqualityComparer.GetHashCode(a); + } + + public static int GetHashCode(object? a) + { + return RuntimeHelpers.GetHashCode(a); + } + } +} diff --git a/src/roslyn-analyzers/src/Utilities/Compiler/WellKnownTypeProvider.cs b/src/roslyn-analyzers/src/Utilities/Compiler/WellKnownTypeProvider.cs index 3bf88da5d97..a9c31353b96 100644 --- a/src/roslyn-analyzers/src/Utilities/Compiler/WellKnownTypeProvider.cs +++ b/src/roslyn-analyzers/src/Utilities/Compiler/WellKnownTypeProvider.cs @@ -4,6 +4,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; @@ -62,6 +63,8 @@ public static WellKnownTypeProvider GetOrCreate(Compilation compilation) /// private readonly ConcurrentDictionary _fullNameToTypeMap; + private ConcurrentCache>? _getTypesCache; + #if !NETSTANDARD1_3 // Assuming we're on .NET Standard 2.0 or later, cache the type names that are probably compile time constants. /// /// Static cache of full type names (with namespaces) to namespace name parts, @@ -78,6 +81,60 @@ public static WellKnownTypeProvider GetOrCreate(Compilation compilation) new(StringComparer.Ordinal); #endif + internal ImmutableArray GetTypesByMetadataName(string fullyQualifiedMetadataName) + { + var getTypesCache = LazyInitializer.EnsureInitialized( + ref _getTypesCache, static () => new ConcurrentCache>(50, ReferenceEqualityComparer.Instance))!; + + if (!getTypesCache.TryGetValue(fullyQualifiedMetadataName, out ImmutableArray val)) + { + val = getTypesByMetadataNameImpl(); + var result = getTypesCache.TryAdd(fullyQualifiedMetadataName, val); + Debug.Assert(result + || !getTypesCache.TryGetValue(fullyQualifiedMetadataName, out var addedArray) // Could fail if the type was already evicted from the cache + || Enumerable.SequenceEqual(addedArray, val, ReferenceEqualityComparer.Instance)); + } + + return val; + + ImmutableArray getTypesByMetadataNameImpl() + { + ArrayBuilder? typesByMetadataName = null; + + // Start with the current assembly, then corlib, then look through all references, to mimic GetTypeByMetadataName search order. + + addIfNotNull(Compilation.Assembly.GetTypeByMetadataName(fullyQualifiedMetadataName)); + + var corLib = Compilation.ObjectType.ContainingAssembly; + + if (!ReferenceEquals(corLib, Compilation.Assembly)) + { + addIfNotNull(corLib.GetTypeByMetadataName(fullyQualifiedMetadataName)); + } + + foreach (var referencedAssembly in Compilation.SourceModule.ReferencedAssemblySymbols) + { + if (ReferenceEquals(referencedAssembly, corLib)) + { + continue; + } + + addIfNotNull(referencedAssembly.GetTypeByMetadataName(fullyQualifiedMetadataName)); + } + + return typesByMetadataName?.ToImmutableAndFree() ?? ImmutableArray.Empty; + + void addIfNotNull(INamedTypeSymbol? toAdd) + { + if (toAdd != null) + { + typesByMetadataName ??= ArrayBuilder.GetInstance(); + typesByMetadataName.Add(toAdd); + } + } + } + } + /// /// Attempts to get the type by the full type name. /// diff --git a/src/roslyn/Directory.Solution.props b/src/roslyn/Directory.Solution.props new file mode 100644 index 00000000000..d6f31c666aa --- /dev/null +++ b/src/roslyn/Directory.Solution.props @@ -0,0 +1,8 @@ + + + + + true + + + \ No newline at end of file diff --git a/src/roslyn/eng/Build.props b/src/roslyn/eng/Build.props new file mode 100644 index 00000000000..894ba2583a3 --- /dev/null +++ b/src/roslyn/eng/Build.props @@ -0,0 +1,9 @@ + + + + + + true + + + \ No newline at end of file diff --git a/src/roslyn/eng/DotNetBuild.props b/src/roslyn/eng/DotNetBuild.props index e508693e89a..758d0125854 100644 --- a/src/roslyn/eng/DotNetBuild.props +++ b/src/roslyn/eng/DotNetBuild.props @@ -27,7 +27,6 @@ $(InnerBuildArgs) /p:Projects="$(InnerSourceBuildRepoRoot)Roslyn.sln" - $(InnerBuildArgs) /p:RestoreUseStaticGraphEvaluation=false diff --git a/src/roslyn/eng/build.ps1 b/src/roslyn/eng/build.ps1 index e2d2d58e609..fb1afbc1c24 100644 --- a/src/roslyn/eng/build.ps1 +++ b/src/roslyn/eng/build.ps1 @@ -266,8 +266,6 @@ function BuildSolution() { $generateDocumentationFile = if ($skipDocumentation) { "/p:GenerateDocumentationFile=false" } else { "" } $roslynUseHardLinks = if ($ci) { "/p:ROSLYNUSEHARDLINKS=true" } else { "" } - $restoreUseStaticGraphEvaluation = $true - try { MSBuild $toolsetBuildProj ` $bl ` @@ -287,7 +285,6 @@ function BuildSolution() { /p:TreatWarningsAsErrors=$warnAsError ` /p:EnableNgenOptimization=$applyOptimizationData ` /p:IbcOptimizationDataDir=$ibcDir ` - /p:RestoreUseStaticGraphEvaluation=$restoreUseStaticGraphEvaluation ` /p:VisualStudioIbcDrop=$ibcDropName ` /p:VisualStudioDropAccessToken=$officialVisualStudioDropAccessToken ` $suppressExtensionDeployment ` diff --git a/src/roslyn/eng/build.sh b/src/roslyn/eng/build.sh index 53fd09baa44..87c1f7a03f1 100755 --- a/src/roslyn/eng/build.sh +++ b/src/roslyn/eng/build.sh @@ -80,7 +80,6 @@ prepare_machine=false warn_as_error=false properties="" source_build=false -restoreUseStaticGraphEvaluation=true solution_to_build="Compilers.slnf" args="" @@ -174,10 +173,8 @@ while [[ $# > 0 ]]; do --warnaserror) warn_as_error=true ;; - --sourcebuild) + --sourcebuild|-sb) source_build=true - # RestoreUseStaticGraphEvaluation will cause prebuilts - restoreUseStaticGraphEvaluation=false ;; --solution) solution_to_build=$2 @@ -307,7 +304,6 @@ function BuildSolution { /p:Publish=$publish \ /p:Sign=$sign \ /p:RunAnalyzersDuringBuild=$run_analyzers \ - /p:RestoreUseStaticGraphEvaluation=$restoreUseStaticGraphEvaluation \ /p:BootstrapBuildPath="$bootstrap_dir" \ /p:ContinuousIntegrationBuild=$ci \ /p:TreatWarningsAsErrors=true \ diff --git a/src/roslyn/eng/targets/GenerateAnalyzerNuspec.targets b/src/roslyn/eng/targets/GenerateAnalyzerNuspec.targets index cd2717add40..7e61d77e5f0 100644 --- a/src/roslyn/eng/targets/GenerateAnalyzerNuspec.targets +++ b/src/roslyn/eng/targets/GenerateAnalyzerNuspec.targets @@ -111,8 +111,12 @@ + + true + + - diff --git a/src/roslyn/eng/targets/Settings.props b/src/roslyn/eng/targets/Settings.props index 6d23d849913..d2f75075882 100644 --- a/src/roslyn/eng/targets/Settings.props +++ b/src/roslyn/eng/targets/Settings.props @@ -20,7 +20,8 @@ CommonExtensions Microsoft\VBCSharp\LanguageServices - true + + true true diff --git a/src/roslyn/eng/test-determinism.ps1 b/src/roslyn/eng/test-determinism.ps1 index 18ef2f3fb1d..44f2a173b61 100644 --- a/src/roslyn/eng/test-determinism.ps1 +++ b/src/roslyn/eng/test-determinism.ps1 @@ -57,8 +57,6 @@ function Run-Build([string]$rootDir, [string]$logFileName) { Stop-Processes - $restoreUseStaticGraphEvaluation = $true - Write-Host "Building $solution using $bootstrapDir" MSBuild $toolsetBuildProj ` /p:Projects=$solution ` @@ -73,7 +71,6 @@ function Run-Build([string]$rootDir, [string]$logFileName) { /p:DeterministicSourcePaths=true ` /p:RunAnalyzers=false ` /p:RunAnalyzersDuringBuild=false ` - /p:RestoreUseStaticGraphEvaluation=$restoreUseStaticGraphEvaluation ` /bl:$logFilePath Stop-Processes diff --git a/src/roslyn/eng/test-rebuild.ps1 b/src/roslyn/eng/test-rebuild.ps1 index 1401cb308e4..223b40102cb 100644 --- a/src/roslyn/eng/test-rebuild.ps1 +++ b/src/roslyn/eng/test-rebuild.ps1 @@ -45,6 +45,7 @@ try { " --assembliesPath `"$ArtifactsDir/obj/`"" + # Rebuilds with output differences + " --exclude net472\Microsoft.CodeAnalysis.EditorFeatures.dll" + " --exclude net472\Microsoft.CodeAnalysis.EditorFeatures.Wpf.dll" + " --exclude net472\Microsoft.VisualStudio.LanguageServices.CSharp.dll" + " --exclude net472\Microsoft.VisualStudio.LanguageServices.dll" + diff --git a/src/roslyn/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs b/src/roslyn/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs index 5f0caa5bd3d..ecc379f4611 100644 --- a/src/roslyn/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs +++ b/src/roslyn/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs @@ -309,7 +309,7 @@ static Symbol getAttributeTarget(Binder current) { SourcePropertyAccessorSymbol { MethodKind: MethodKind.PropertySet } setter => getSetterParameters(setter), MethodSymbol methodSymbol => methodSymbol.Parameters, - ParameterSymbol parameter => getAllParameters(parameter), + ParameterSymbol parameter when parameter.ContainingSymbol is not NamedTypeSymbol => getAllParameters(parameter), TypeParameterSymbol typeParameter => getMethodParametersFromTypeParameter(typeParameter), PropertySymbol property => property.Parameters, NamedTypeSymbol namedType when namedType.IsDelegateType() => getDelegateParameters(namedType), diff --git a/src/roslyn/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs b/src/roslyn/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs index b253e34caf7..4e2f53d9a37 100644 --- a/src/roslyn/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs +++ b/src/roslyn/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs @@ -35817,7 +35817,7 @@ public static void M2([System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(o Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x2").WithLocation(7, 1)); } - [Fact(Skip = "Tracked by https://github.com/dotnet/roslyn/issues/76130 : failure in creating binder in GetEnclosingBinder")] + [Fact] public void Nullability_Attribute_11() { var src = """ @@ -35833,7 +35833,7 @@ public void Nullability_Attribute_11() static class E { - extension([ /**/ System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(o)) /**/ ] ref int? i) + extension([ /**/ System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(o)) /**/ ] [System.Diagnostics.CodeAnalysis.NotNullIfNotNull(nameof(i))] ref int? i) { public void M(object? o) => throw null!; } diff --git a/src/roslyn/src/EditorFeatures/CSharp/InlineRename/CSharpEditorInlineRenameService.cs b/src/roslyn/src/EditorFeatures/CSharp/InlineRename/CSharpEditorInlineRenameService.cs index cb4855b91cf..932bedf79f7 100644 --- a/src/roslyn/src/EditorFeatures/CSharp/InlineRename/CSharpEditorInlineRenameService.cs +++ b/src/roslyn/src/EditorFeatures/CSharp/InlineRename/CSharpEditorInlineRenameService.cs @@ -16,6 +16,7 @@ using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.CSharp.InlineRename; @@ -57,7 +58,7 @@ await TryGetSurroundingNodeSpanAsync(renameDefinition.D var (symbol, _, _) = await symbolService.GetSymbolProjectAndBoundSpanAsync( renameDefinition.Document, semanticModel, textSpan.Start, cancellationToken).ConfigureAwait(true); var docComment = symbol?.GetDocumentationCommentXml(expandIncludes: true, cancellationToken: cancellationToken); - if (!string.IsNullOrWhiteSpace(docComment)) + if (!RoslynString.IsNullOrWhiteSpace(docComment)) { var filePath = renameDefinition.Document.FilePath; if (filePath != null) diff --git a/src/roslyn/src/EditorFeatures/CSharp/Microsoft.CodeAnalysis.CSharp.EditorFeatures.csproj b/src/roslyn/src/EditorFeatures/CSharp/Microsoft.CodeAnalysis.CSharp.EditorFeatures.csproj index 29acf31963d..7087f7a3839 100644 --- a/src/roslyn/src/EditorFeatures/CSharp/Microsoft.CodeAnalysis.CSharp.EditorFeatures.csproj +++ b/src/roslyn/src/EditorFeatures/CSharp/Microsoft.CodeAnalysis.CSharp.EditorFeatures.csproj @@ -1,12 +1,12 @@  - + Library Microsoft.CodeAnalysis.Editor.CSharp - $(NetVS);netstandard2.0 + net472 + true true - full true diff --git a/src/roslyn/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteData.cs b/src/roslyn/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteData.cs index 0c7315a8acb..b9d7a6a0a38 100644 --- a/src/roslyn/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteData.cs +++ b/src/roslyn/src/EditorFeatures/CSharp/StringCopyPaste/StringCopyPasteData.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.EmbeddedLanguages.VirtualChars; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.CSharp.StringCopyPaste; @@ -39,7 +40,7 @@ internal sealed class StringCopyPasteData(ImmutableArray public static StringCopyPasteData? FromJson(string? json) { - if (string.IsNullOrWhiteSpace(json)) + if (RoslynString.IsNullOrWhiteSpace(json)) return null; try diff --git a/src/roslyn/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs b/src/roslyn/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs index 8f0e44eee1a..077822b7d8a 100644 --- a/src/roslyn/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs +++ b/src/roslyn/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/SymbolCompletionProviderTests.cs @@ -8785,8 +8785,8 @@ void goo() var expectedDescription = $""" ({FeaturesResources.field}) int C.x - {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} - {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} """; @@ -8825,9 +8825,9 @@ void goo() var expectedDescription = $""" ({FeaturesResources.field}) int C.x - {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} - {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} - {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} """; @@ -8869,8 +8869,8 @@ void goo() var expectedDescription = $""" ({FeaturesResources.field}) int C.x - {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} - {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} """; @@ -8916,9 +8916,9 @@ void goo() var expectedDescription = $""" void G.DoGStuff() - {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Not_Available)} - {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Available)} - {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} """; @@ -8981,8 +8981,8 @@ void M() var expectedDescription = $""" ({FeaturesResources.local_variable}) int xyz - {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} - {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} """; diff --git a/src/roslyn/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs b/src/roslyn/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs index 0bd59bebb8a..12d8e25bb65 100644 --- a/src/roslyn/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs +++ b/src/roslyn/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs @@ -6295,8 +6295,8 @@ void goo() """; var expectedDescription = Usage($""" - {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} - {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} """, expectsWarningGlyph: true); @@ -6331,8 +6331,8 @@ void goo() """; var expectedDescription = Usage($""" - {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Not_Available)} - {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Available)} {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} """, expectsWarningGlyph: true); @@ -6371,9 +6371,9 @@ void goo() var expectedDescription = Usage( $""" - {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} - {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} - {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} """, @@ -6415,8 +6415,8 @@ void goo() """; var expectedDescription = Usage($""" - {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} - {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} """, expectsWarningGlyph: true); @@ -6507,8 +6507,8 @@ void M() await VerifyWithReferenceWorkerAsync(markup, [MainDescription($"({FeaturesResources.local_variable}) int x"), Usage($""" - {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} - {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} """, expectsWarningGlyph: true)]); diff --git a/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/AttributeSignatureHelpProviderTests.cs b/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/AttributeSignatureHelpProviderTests.cs index 358bdc8297f..d77d2365bd0 100644 --- a/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/AttributeSignatureHelpProviderTests.cs +++ b/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/AttributeSignatureHelpProviderTests.cs @@ -998,7 +998,14 @@ void Goo() """; - var expectedDescription = new SignatureHelpTestItem($"Secret()\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0); + var expectedDescription = new SignatureHelpTestItem($""" + Secret() + + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} + + {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} + """, currentParameterIndex: 0); await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); } @@ -1036,7 +1043,14 @@ void Goo() """; - var expectedDescription = new SignatureHelpTestItem($"Secret()\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0); + var expectedDescription = new SignatureHelpTestItem($""" + Secret() + + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} + + {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} + """, currentParameterIndex: 0); await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); } diff --git a/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/ConstructorInitializerSignatureHelpProviderTests.cs b/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/ConstructorInitializerSignatureHelpProviderTests.cs index 4117c9b761b..b49b86ca81a 100644 --- a/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/ConstructorInitializerSignatureHelpProviderTests.cs +++ b/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/ConstructorInitializerSignatureHelpProviderTests.cs @@ -597,7 +597,14 @@ public SuperSecret(int secret) : base($$ """; - var expectedDescription = new SignatureHelpTestItem($"Secret(int secret)\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0); + var expectedDescription = new SignatureHelpTestItem($""" + Secret(int secret) + + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} + + {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} + """, currentParameterIndex: 0); await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); } @@ -638,7 +645,14 @@ public SuperSecret(int secret) : base($$ """; - var expectedDescription = new SignatureHelpTestItem($"Secret(int secret)\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0); + var expectedDescription = new SignatureHelpTestItem($""" + Secret(int secret) + + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} + + {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} + """, currentParameterIndex: 0); await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); } diff --git a/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/ElementAccessExpressionSignatureHelpProviderTests.cs b/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/ElementAccessExpressionSignatureHelpProviderTests.cs index 7190b7c0994..b227f52f11f 100644 --- a/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/ElementAccessExpressionSignatureHelpProviderTests.cs +++ b/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/ElementAccessExpressionSignatureHelpProviderTests.cs @@ -816,7 +816,14 @@ void goo() """; - var expectedDescription = new SignatureHelpTestItem($"int C[int z]\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0); + var expectedDescription = new SignatureHelpTestItem($""" + int C[int z] + + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} + + {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} + """, currentParameterIndex: 0); await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); } @@ -858,7 +865,14 @@ void goo() """; - var expectedDescription = new SignatureHelpTestItem($"int C[int z]\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0); + var expectedDescription = new SignatureHelpTestItem($""" + int C[int z] + + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} + + {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} + """, currentParameterIndex: 0); await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); } diff --git a/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/GenericNameSignatureHelpProviderTests.cs b/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/GenericNameSignatureHelpProviderTests.cs index 5e89b9a828a..4f9f75a7fae 100644 --- a/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/GenericNameSignatureHelpProviderTests.cs +++ b/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/GenericNameSignatureHelpProviderTests.cs @@ -782,7 +782,14 @@ void goo() """; - var expectedDescription = new SignatureHelpTestItem($"D\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0); + var expectedDescription = new SignatureHelpTestItem($""" + D + + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} + + {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} + """, currentParameterIndex: 0); await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); } @@ -820,7 +827,14 @@ void goo() """; - var expectedDescription = new SignatureHelpTestItem($"D\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0); + var expectedDescription = new SignatureHelpTestItem($""" + D + + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} + + {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} + """, currentParameterIndex: 0); await VerifyItemWithReferenceWorkerAsync(markup, [expectedDescription], false); } diff --git a/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/InvocationExpressionSignatureHelpProviderTests.cs b/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/InvocationExpressionSignatureHelpProviderTests.cs index 2b330a1c4ed..2abfcf0a51a 100644 --- a/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/InvocationExpressionSignatureHelpProviderTests.cs +++ b/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/InvocationExpressionSignatureHelpProviderTests.cs @@ -2082,8 +2082,8 @@ void goo() await VerifyItemWithReferenceWorkerAsync(markup, [new SignatureHelpTestItem($""" void C.bar() - {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} - {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} """, currentParameterIndex: 0)], hideAdvancedMembers: false); @@ -2126,8 +2126,8 @@ void goo() await VerifyItemWithReferenceWorkerAsync(markup, [new SignatureHelpTestItem($""" void C.bar() - {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} - {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} """, currentParameterIndex: 0)], hideAdvancedMembers: false); @@ -2341,8 +2341,8 @@ void Shared() await VerifyItemWithReferenceWorkerAsync(markup, [new SignatureHelpTestItem($""" void C.Do(int x) - {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} - {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} """, currentParameterIndex: 0)], hideAdvancedMembers: false); @@ -2613,8 +2613,8 @@ void goo() expectedItems.Add(new SignatureHelpTestItem($""" void C.M(Action arg1, object arg2, bool flag) - {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} - {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} """, currentParameterIndex: 0)); @@ -2625,8 +2625,8 @@ void C.M(Action arg1, object arg2, bool flag) expectedItems.Add(new SignatureHelpTestItem($""" void C.M(Action arg1, T arg2, bool flag) - {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} - {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} """, currentParameterIndex: 0)); diff --git a/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/ObjectCreationExpressionSignatureHelpProviderTests.cs b/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/ObjectCreationExpressionSignatureHelpProviderTests.cs index a6932555fd9..45faed92ed8 100644 --- a/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/ObjectCreationExpressionSignatureHelpProviderTests.cs +++ b/src/roslyn/src/EditorFeatures/CSharpTest/SignatureHelp/ObjectCreationExpressionSignatureHelpProviderTests.cs @@ -615,7 +615,14 @@ void goo() """; await VerifyItemWithReferenceWorkerAsync( - markup, [new($"D()\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0)], false); + markup, [new($""" + D() + + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available)} + + {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} + """, currentParameterIndex: 0)], false); } [Fact] @@ -653,7 +660,14 @@ void goo() """; await VerifyItemWithReferenceWorkerAsync( - markup, [new($"D()\r\n\r\n{string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}", currentParameterIndex: 0)], false); + markup, [new($""" + D() + + {string.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)} + {string.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)} + + {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts} + """, currentParameterIndex: 0)], false); } [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1067933")] diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Peek/IPeekableItemFactory.cs b/src/roslyn/src/EditorFeatures/Core.Wpf/Peek/IPeekableItemFactory.cs index 940e9dc3460..993ea88ed53 100644 --- a/src/roslyn/src/EditorFeatures/Core.Wpf/Peek/IPeekableItemFactory.cs +++ b/src/roslyn/src/EditorFeatures/Core.Wpf/Peek/IPeekableItemFactory.cs @@ -4,9 +4,16 @@ #nullable disable +using System; using System.Collections.Generic; +using System.Composition; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Implementation.Peek; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.MetadataAsSource; +using Microsoft.CodeAnalysis.Options; using Microsoft.VisualStudio.Language.Intellisense; namespace Microsoft.CodeAnalysis.Editor.Peek; @@ -15,3 +22,14 @@ public interface IPeekableItemFactory { Task> GetPeekableItemsAsync(ISymbol symbol, Project project, IPeekResultFactory peekResultFactory, CancellationToken cancellationToken); } + +/// +/// Legacy export for xaml. They should move to IXamlPeekableItemFactory once this is inserted. +/// +[Export(typeof(IPeekableItemFactory)), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class EditorPeekableItemFactory( + IMetadataAsSourceFileService metadataAsSourceFileService, + IGlobalOptionService globalOptions, + IThreadingContext threadingContext) : PeekableItemFactory(metadataAsSourceFileService, globalOptions, threadingContext); diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Adornments/AbstractAdornmentManager.cs b/src/roslyn/src/EditorFeatures/Core/Adornments/AbstractAdornmentManager.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Adornments/AbstractAdornmentManager.cs rename to src/roslyn/src/EditorFeatures/Core/Adornments/AbstractAdornmentManager.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Adornments/AbstractAdornmentManagerProvider.cs b/src/roslyn/src/EditorFeatures/Core/Adornments/AbstractAdornmentManagerProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Adornments/AbstractAdornmentManagerProvider.cs rename to src/roslyn/src/EditorFeatures/Core/Adornments/AbstractAdornmentManagerProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Adornments/BrushTag.cs b/src/roslyn/src/EditorFeatures/Core/Adornments/BrushTag.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Adornments/BrushTag.cs rename to src/roslyn/src/EditorFeatures/Core/Adornments/BrushTag.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Adornments/GraphicsResult.cs b/src/roslyn/src/EditorFeatures/Core/Adornments/GraphicsResult.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Adornments/GraphicsResult.cs rename to src/roslyn/src/EditorFeatures/Core/Adornments/GraphicsResult.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Adornments/GraphicsTag.cs b/src/roslyn/src/EditorFeatures/Core/Adornments/GraphicsTag.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Adornments/GraphicsTag.cs rename to src/roslyn/src/EditorFeatures/Core/Adornments/GraphicsTag.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/AsyncCompletion/LanguageServerSnippetExpanderAdapter.cs b/src/roslyn/src/EditorFeatures/Core/AsyncCompletion/LanguageServerSnippetExpanderAdapter.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/AsyncCompletion/LanguageServerSnippetExpanderAdapter.cs rename to src/roslyn/src/EditorFeatures/Core/AsyncCompletion/LanguageServerSnippetExpanderAdapter.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorContext.cs b/src/roslyn/src/EditorFeatures/Core/BackgroundWorkIndicator/BackgroundWorkIndicatorContext.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorContext.cs rename to src/roslyn/src/EditorFeatures/Core/BackgroundWorkIndicator/BackgroundWorkIndicatorContext.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorScope.cs b/src/roslyn/src/EditorFeatures/Core/BackgroundWorkIndicator/BackgroundWorkIndicatorScope.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/BackgroundWorkIndicatorScope.cs rename to src/roslyn/src/EditorFeatures/Core/BackgroundWorkIndicator/BackgroundWorkIndicatorScope.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/WpfBackgroundWorkIndicatorFactory.cs b/src/roslyn/src/EditorFeatures/Core/BackgroundWorkIndicator/WpfBackgroundWorkIndicatorFactory.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/BackgroundWorkIndicator/WpfBackgroundWorkIndicatorFactory.cs rename to src/roslyn/src/EditorFeatures/Core/BackgroundWorkIndicator/WpfBackgroundWorkIndicatorFactory.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/BraceMatching/BraceMatchingTypeFormatDefinitions.cs b/src/roslyn/src/EditorFeatures/Core/BraceMatching/BraceMatchingTypeFormatDefinitions.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/BraceMatching/BraceMatchingTypeFormatDefinitions.cs rename to src/roslyn/src/EditorFeatures/Core/BraceMatching/BraceMatchingTypeFormatDefinitions.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Classification/ClassificationTypeFormatDefinitions.cs b/src/roslyn/src/EditorFeatures/Core/Classification/ClassificationTypeFormatDefinitions.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Classification/ClassificationTypeFormatDefinitions.cs rename to src/roslyn/src/EditorFeatures/Core/Classification/ClassificationTypeFormatDefinitions.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/ConflictTagDefinition.cs b/src/roslyn/src/EditorFeatures/Core/ConflictTagDefinition.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/ConflictTagDefinition.cs rename to src/roslyn/src/EditorFeatures/Core/ConflictTagDefinition.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/DependencyObjectExtensions.cs b/src/roslyn/src/EditorFeatures/Core/DependencyObjectExtensions.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/DependencyObjectExtensions.cs rename to src/roslyn/src/EditorFeatures/Core/DependencyObjectExtensions.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/EditAndContinue/ActiveStatementTagFormatDefinition.cs b/src/roslyn/src/EditorFeatures/Core/EditAndContinue/ActiveStatementTagFormatDefinition.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/EditAndContinue/ActiveStatementTagFormatDefinition.cs rename to src/roslyn/src/EditorFeatures/Core/EditAndContinue/ActiveStatementTagFormatDefinition.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/EditAndContinue/EditAndContinueErrorTypeFormatDefinition.cs b/src/roslyn/src/EditorFeatures/Core/EditAndContinue/EditAndContinueErrorTypeFormatDefinition.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/EditAndContinue/EditAndContinueErrorTypeFormatDefinition.cs rename to src/roslyn/src/EditorFeatures/Core/EditAndContinue/EditAndContinueErrorTypeFormatDefinition.cs diff --git a/src/roslyn/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs b/src/roslyn/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs index 5ca93c60e33..5362ae3d917 100644 --- a/src/roslyn/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs +++ b/src/roslyn/src/EditorFeatures/Core/EditAndContinue/EditAndContinueLanguageService.cs @@ -175,7 +175,7 @@ private async ValueTask BreakStateOrCapabilitiesChangedAsync(bool? inBreakState, // We start the operation but do not wait for it to complete. // The tracking session is cancelled when we exit the break state. - Debug.Assert(solution != null); + Contract.ThrowIfNull(solution); GetActiveStatementTrackingService().StartTracking(solution, session); } } diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/EditorFeaturesWpfResources.resx b/src/roslyn/src/EditorFeatures/Core/EditorFeaturesWpfResources.resx similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/EditorFeaturesWpfResources.resx rename to src/roslyn/src/EditorFeatures/Core/EditorFeaturesWpfResources.resx diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/ExternalAccess/VSTypeScript/VSTypeScriptSignatureHelpClassifierProvider.cs b/src/roslyn/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptSignatureHelpClassifierProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/ExternalAccess/VSTypeScript/VSTypeScriptSignatureHelpClassifierProvider.cs rename to src/roslyn/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/VSTypeScriptSignatureHelpClassifierProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/IDebuggerTextView2.cs b/src/roslyn/src/EditorFeatures/Core/IDebuggerTextView2.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/IDebuggerTextView2.cs rename to src/roslyn/src/EditorFeatures/Core/IDebuggerTextView2.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/IWpfDifferenceViewerExtensions.cs b/src/roslyn/src/EditorFeatures/Core/IWpfDifferenceViewerExtensions.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/IWpfDifferenceViewerExtensions.cs rename to src/roslyn/src/EditorFeatures/Core/IWpfDifferenceViewerExtensions.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/IWpfTextViewExtensions.cs b/src/roslyn/src/EditorFeatures/Core/IWpfTextViewExtensions.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/IWpfTextViewExtensions.cs rename to src/roslyn/src/EditorFeatures/Core/IWpfTextViewExtensions.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/IWpfThemeService.cs b/src/roslyn/src/EditorFeatures/Core/IWpfThemeService.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/IWpfThemeService.cs rename to src/roslyn/src/EditorFeatures/Core/IWpfThemeService.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineDiagnostics/AbstractDiagnosticsTaggerProvider.SingleDiagnosticKindPullTaggerProvider.cs b/src/roslyn/src/EditorFeatures/Core/InlineDiagnostics/AbstractDiagnosticsTaggerProvider.SingleDiagnosticKindPullTaggerProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineDiagnostics/AbstractDiagnosticsTaggerProvider.SingleDiagnosticKindPullTaggerProvider.cs rename to src/roslyn/src/EditorFeatures/Core/InlineDiagnostics/AbstractDiagnosticsTaggerProvider.SingleDiagnosticKindPullTaggerProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineDiagnostics/AbstractDiagnosticsTaggerProvider.cs b/src/roslyn/src/EditorFeatures/Core/InlineDiagnostics/AbstractDiagnosticsTaggerProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineDiagnostics/AbstractDiagnosticsTaggerProvider.cs rename to src/roslyn/src/EditorFeatures/Core/InlineDiagnostics/AbstractDiagnosticsTaggerProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsAdornmentManager.cs b/src/roslyn/src/EditorFeatures/Core/InlineDiagnostics/InlineDiagnosticsAdornmentManager.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsAdornmentManager.cs rename to src/roslyn/src/EditorFeatures/Core/InlineDiagnostics/InlineDiagnosticsAdornmentManager.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsAdornmentManagerProvider.cs b/src/roslyn/src/EditorFeatures/Core/InlineDiagnostics/InlineDiagnosticsAdornmentManagerProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsAdornmentManagerProvider.cs rename to src/roslyn/src/EditorFeatures/Core/InlineDiagnostics/InlineDiagnosticsAdornmentManagerProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsFormatDefinition.cs b/src/roslyn/src/EditorFeatures/Core/InlineDiagnostics/InlineDiagnosticsFormatDefinition.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsFormatDefinition.cs rename to src/roslyn/src/EditorFeatures/Core/InlineDiagnostics/InlineDiagnosticsFormatDefinition.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTag.cs b/src/roslyn/src/EditorFeatures/Core/InlineDiagnostics/InlineDiagnosticsTag.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTag.cs rename to src/roslyn/src/EditorFeatures/Core/InlineDiagnostics/InlineDiagnosticsTag.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTaggerProvider.cs b/src/roslyn/src/EditorFeatures/Core/InlineDiagnostics/InlineDiagnosticsTaggerProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineDiagnostics/InlineDiagnosticsTaggerProvider.cs rename to src/roslyn/src/EditorFeatures/Core/InlineDiagnostics/InlineDiagnosticsTaggerProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineHints/CachedAdornmentTagSpan.cs b/src/roslyn/src/EditorFeatures/Core/InlineHints/CachedAdornmentTagSpan.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineHints/CachedAdornmentTagSpan.cs rename to src/roslyn/src/EditorFeatures/Core/InlineHints/CachedAdornmentTagSpan.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsFormatDefinition.cs b/src/roslyn/src/EditorFeatures/Core/InlineHints/InlineHintsFormatDefinition.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsFormatDefinition.cs rename to src/roslyn/src/EditorFeatures/Core/InlineHints/InlineHintsFormatDefinition.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsKeyProcessorProvider.cs b/src/roslyn/src/EditorFeatures/Core/InlineHints/InlineHintsKeyProcessorProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsKeyProcessorProvider.cs rename to src/roslyn/src/EditorFeatures/Core/InlineHints/InlineHintsKeyProcessorProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTag.cs b/src/roslyn/src/EditorFeatures/Core/InlineHints/InlineHintsTag.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTag.cs rename to src/roslyn/src/EditorFeatures/Core/InlineHints/InlineHintsTag.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTagger.cs b/src/roslyn/src/EditorFeatures/Core/InlineHints/InlineHintsTagger.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTagger.cs rename to src/roslyn/src/EditorFeatures/Core/InlineHints/InlineHintsTagger.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTaggerProvider.cs b/src/roslyn/src/EditorFeatures/Core/InlineHints/InlineHintsTaggerProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsTaggerProvider.cs rename to src/roslyn/src/EditorFeatures/Core/InlineHints/InlineHintsTaggerProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsViewOptionsStorage.cs b/src/roslyn/src/EditorFeatures/Core/InlineHints/InlineHintsViewOptionsStorage.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineHints/InlineHintsViewOptionsStorage.cs rename to src/roslyn/src/EditorFeatures/Core/InlineHints/InlineHintsViewOptionsStorage.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs b/src/roslyn/src/EditorFeatures/Core/InlineRename/CommandHandlers/RenameCommandHandler.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/CommandHandlers/RenameCommandHandler.cs rename to src/roslyn/src/EditorFeatures/Core/InlineRename/CommandHandlers/RenameCommandHandler.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/HighlightTags/RenameConflictTagDefinition.cs b/src/roslyn/src/EditorFeatures/Core/InlineRename/HighlightTags/RenameConflictTagDefinition.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/HighlightTags/RenameConflictTagDefinition.cs rename to src/roslyn/src/EditorFeatures/Core/InlineRename/HighlightTags/RenameConflictTagDefinition.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/HighlightTags/RenameFieldBackgroundAndBorderTagDefinition.cs b/src/roslyn/src/EditorFeatures/Core/InlineRename/HighlightTags/RenameFieldBackgroundAndBorderTagDefinition.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/HighlightTags/RenameFieldBackgroundAndBorderTagDefinition.cs rename to src/roslyn/src/EditorFeatures/Core/InlineRename/HighlightTags/RenameFieldBackgroundAndBorderTagDefinition.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/HighlightTags/RenameFixupTagDefinition.cs b/src/roslyn/src/EditorFeatures/Core/InlineRename/HighlightTags/RenameFixupTagDefinition.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/HighlightTags/RenameFixupTagDefinition.cs rename to src/roslyn/src/EditorFeatures/Core/InlineRename/HighlightTags/RenameFixupTagDefinition.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/Taggers/ClassificationFormatDefinitions.cs b/src/roslyn/src/EditorFeatures/Core/InlineRename/Taggers/ClassificationFormatDefinitions.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/Taggers/ClassificationFormatDefinitions.cs rename to src/roslyn/src/EditorFeatures/Core/InlineRename/Taggers/ClassificationFormatDefinitions.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml b/src/roslyn/src/EditorFeatures/Core/InlineRename/UI/Adornment/RenameFlyout.xaml similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml rename to src/roslyn/src/EditorFeatures/Core/InlineRename/UI/Adornment/RenameFlyout.xaml diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml.cs b/src/roslyn/src/EditorFeatures/Core/InlineRename/UI/Adornment/RenameFlyout.xaml.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyout.xaml.cs rename to src/roslyn/src/EditorFeatures/Core/InlineRename/UI/Adornment/RenameFlyout.xaml.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs b/src/roslyn/src/EditorFeatures/Core/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs rename to src/roslyn/src/EditorFeatures/Core/InlineRename/UI/Adornment/RenameFlyoutViewModel.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameUserInputTextBox.xaml b/src/roslyn/src/EditorFeatures/Core/InlineRename/UI/Adornment/RenameUserInputTextBox.xaml similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameUserInputTextBox.xaml rename to src/roslyn/src/EditorFeatures/Core/InlineRename/UI/Adornment/RenameUserInputTextBox.xaml diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameUserInputTextBox.xaml.cs b/src/roslyn/src/EditorFeatures/Core/InlineRename/UI/Adornment/RenameUserInputTextBox.xaml.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/RenameUserInputTextBox.xaml.cs rename to src/roslyn/src/EditorFeatures/Core/InlineRename/UI/Adornment/RenameUserInputTextBox.xaml.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/IInlineRenameColorUpdater.cs b/src/roslyn/src/EditorFeatures/Core/InlineRename/UI/IInlineRenameColorUpdater.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/IInlineRenameColorUpdater.cs rename to src/roslyn/src/EditorFeatures/Core/InlineRename/UI/IInlineRenameColorUpdater.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/IRenameUserInput.cs b/src/roslyn/src/EditorFeatures/Core/InlineRename/UI/IRenameUserInput.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/IRenameUserInput.cs rename to src/roslyn/src/EditorFeatures/Core/InlineRename/UI/IRenameUserInput.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/InlineRenameAdornment.cs b/src/roslyn/src/EditorFeatures/Core/InlineRename/UI/InlineRenameAdornment.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/InlineRenameAdornment.cs rename to src/roslyn/src/EditorFeatures/Core/InlineRename/UI/InlineRenameAdornment.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/InlineRenameAdornmentManager.cs b/src/roslyn/src/EditorFeatures/Core/InlineRename/UI/InlineRenameAdornmentManager.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/InlineRenameAdornmentManager.cs rename to src/roslyn/src/EditorFeatures/Core/InlineRename/UI/InlineRenameAdornmentManager.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/InlineRenameAdornmentProvider.cs b/src/roslyn/src/EditorFeatures/Core/InlineRename/UI/InlineRenameAdornmentProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/InlineRenameAdornmentProvider.cs rename to src/roslyn/src/EditorFeatures/Core/InlineRename/UI/InlineRenameAdornmentProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/InlineRenameColors.cs b/src/roslyn/src/EditorFeatures/Core/InlineRename/UI/InlineRenameColors.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/InlineRenameColors.cs rename to src/roslyn/src/EditorFeatures/Core/InlineRename/UI/InlineRenameColors.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/InlineRenameColors.xaml b/src/roslyn/src/EditorFeatures/Core/InlineRename/UI/InlineRenameColors.xaml similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/InlineRenameColors.xaml rename to src/roslyn/src/EditorFeatures/Core/InlineRename/UI/InlineRenameColors.xaml diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/RenameUserInputPresenter.cs b/src/roslyn/src/EditorFeatures/Core/InlineRename/UI/RenameUserInputPresenter.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/RenameUserInputPresenter.cs rename to src/roslyn/src/EditorFeatures/Core/InlineRename/UI/RenameUserInputPresenter.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameStatusControl.xaml b/src/roslyn/src/EditorFeatures/Core/InlineRename/UI/SmartRename/SmartRenameStatusControl.xaml similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameStatusControl.xaml rename to src/roslyn/src/EditorFeatures/Core/InlineRename/UI/SmartRename/SmartRenameStatusControl.xaml diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameStatusControl.xaml.cs b/src/roslyn/src/EditorFeatures/Core/InlineRename/UI/SmartRename/SmartRenameStatusControl.xaml.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameStatusControl.xaml.cs rename to src/roslyn/src/EditorFeatures/Core/InlineRename/UI/SmartRename/SmartRenameStatusControl.xaml.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameUserInputComboBox.xaml b/src/roslyn/src/EditorFeatures/Core/InlineRename/UI/SmartRename/SmartRenameUserInputComboBox.xaml similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameUserInputComboBox.xaml rename to src/roslyn/src/EditorFeatures/Core/InlineRename/UI/SmartRename/SmartRenameUserInputComboBox.xaml diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameUserInputComboBox.xaml.cs b/src/roslyn/src/EditorFeatures/Core/InlineRename/UI/SmartRename/SmartRenameUserInputComboBox.xaml.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameUserInputComboBox.xaml.cs rename to src/roslyn/src/EditorFeatures/Core/InlineRename/UI/SmartRename/SmartRenameUserInputComboBox.xaml.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameViewModel.cs b/src/roslyn/src/EditorFeatures/Core/InlineRename/UI/SmartRename/SmartRenameViewModel.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameViewModel.cs rename to src/roslyn/src/EditorFeatures/Core/InlineRename/UI/SmartRename/SmartRenameViewModel.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameViewModel_Telemetry.cs b/src/roslyn/src/EditorFeatures/Core/InlineRename/UI/SmartRename/SmartRenameViewModel_Telemetry.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/InlineRename/UI/SmartRename/SmartRenameViewModel_Telemetry.cs rename to src/roslyn/src/EditorFeatures/Core/InlineRename/UI/SmartRename/SmartRenameViewModel_Telemetry.cs diff --git a/src/roslyn/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.cs b/src/roslyn/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.cs index 1f461898746..730164f11e8 100644 --- a/src/roslyn/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.cs +++ b/src/roslyn/src/EditorFeatures/Core/IntelliSense/AsyncCompletion/ItemManager.cs @@ -190,7 +190,7 @@ public int Compare(VSCompletionItem? x, VSCompletionItem? y) var yRoslyn = y is not null ? CompletionItemData.GetOrAddDummyRoslynItem(y) : null; // Sort by default comparer of Roslyn CompletionItem - return Comparer.Default.Compare(xRoslyn, yRoslyn); + return Comparer.Default.Compare(xRoslyn, yRoslyn); } } } diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/AbstractInteractiveWindowCommandCompletionProvider.cs b/src/roslyn/src/EditorFeatures/Core/Interactive/AbstractInteractiveWindowCommandCompletionProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/AbstractInteractiveWindowCommandCompletionProvider.cs rename to src/roslyn/src/EditorFeatures/Core/Interactive/AbstractInteractiveWindowCommandCompletionProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/IResettableInteractiveEvaluator.cs b/src/roslyn/src/EditorFeatures/Core/Interactive/IResettableInteractiveEvaluator.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/IResettableInteractiveEvaluator.cs rename to src/roslyn/src/EditorFeatures/Core/Interactive/IResettableInteractiveEvaluator.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InertClassifierProvider.InertClassifier.cs b/src/roslyn/src/EditorFeatures/Core/Interactive/InertClassifierProvider.InertClassifier.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InertClassifierProvider.InertClassifier.cs rename to src/roslyn/src/EditorFeatures/Core/Interactive/InertClassifierProvider.InertClassifier.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InertClassifierProvider.cs b/src/roslyn/src/EditorFeatures/Core/Interactive/InertClassifierProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InertClassifierProvider.cs rename to src/roslyn/src/EditorFeatures/Core/Interactive/InertClassifierProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveCommandContentTypeLanguageService.cs b/src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveCommandContentTypeLanguageService.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveCommandContentTypeLanguageService.cs rename to src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveCommandContentTypeLanguageService.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveCommandHandler.cs b/src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveCommandHandler.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveCommandHandler.cs rename to src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveCommandHandler.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveDocumentNavigationService.cs b/src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveDocumentNavigationService.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveDocumentNavigationService.cs rename to src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveDocumentNavigationService.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveDocumentNavigationServiceFactory.cs b/src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveDocumentNavigationServiceFactory.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveDocumentNavigationServiceFactory.cs rename to src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveDocumentNavigationServiceFactory.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveEvaluator.cs b/src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveEvaluator.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveEvaluator.cs rename to src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveEvaluator.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveEvaluatorResetOptions.cs b/src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveEvaluatorResetOptions.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveEvaluatorResetOptions.cs rename to src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveEvaluatorResetOptions.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveGlobalUndoServiceFactory.cs b/src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveGlobalUndoServiceFactory.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveGlobalUndoServiceFactory.cs rename to src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveGlobalUndoServiceFactory.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractivePasteCommandHandler.cs b/src/roslyn/src/EditorFeatures/Core/Interactive/InteractivePasteCommandHandler.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractivePasteCommandHandler.cs rename to src/roslyn/src/EditorFeatures/Core/Interactive/InteractivePasteCommandHandler.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveSupportsFeatureService.cs b/src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveSupportsFeatureService.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveSupportsFeatureService.cs rename to src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveSupportsFeatureService.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveTextUndoHistoryWorkspaceServiceFactory.cs b/src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveTextUndoHistoryWorkspaceServiceFactory.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveTextUndoHistoryWorkspaceServiceFactory.cs rename to src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveTextUndoHistoryWorkspaceServiceFactory.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveWindowContentTypes.cs b/src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveWindowContentTypes.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveWindowContentTypes.cs rename to src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveWindowContentTypes.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveWindowResetCommand.cs b/src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveWindowResetCommand.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveWindowResetCommand.cs rename to src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveWindowResetCommand.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveWindowWorkspace.cs b/src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveWindowWorkspace.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/InteractiveWindowWorkspace.cs rename to src/roslyn/src/EditorFeatures/Core/Interactive/InteractiveWindowWorkspace.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/ResetInteractive.cs b/src/roslyn/src/EditorFeatures/Core/Interactive/ResetInteractive.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/ResetInteractive.cs rename to src/roslyn/src/EditorFeatures/Core/Interactive/ResetInteractive.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.cs.xlf b/src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.cs.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.cs.xlf rename to src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.cs.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.de.xlf b/src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.de.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.de.xlf rename to src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.de.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.es.xlf b/src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.es.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.es.xlf rename to src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.es.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.fr.xlf b/src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.fr.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.fr.xlf rename to src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.fr.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.it.xlf b/src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.it.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.it.xlf rename to src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.it.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.ja.xlf b/src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.ja.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.ja.xlf rename to src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.ja.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.ko.xlf b/src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.ko.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.ko.xlf rename to src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.ko.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.pl.xlf b/src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.pl.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.pl.xlf rename to src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.pl.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.pt-BR.xlf b/src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.pt-BR.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.pt-BR.xlf rename to src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.pt-BR.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.ru.xlf b/src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.ru.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.ru.xlf rename to src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.ru.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.tr.xlf b/src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.tr.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.tr.xlf rename to src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.tr.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.zh-Hans.xlf b/src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.zh-Hans.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.zh-Hans.xlf rename to src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.zh-Hans.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.zh-Hant.xlf b/src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.zh-Hant.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Interactive/xlf/InteractiveEditorFeaturesResources.zh-Hant.xlf rename to src/roslyn/src/EditorFeatures/Core/Interactive/xlf/InteractiveEditorFeaturesResources.zh-Hant.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Lightup/ISmartRenameSessionFactoryWrapper.cs b/src/roslyn/src/EditorFeatures/Core/Lightup/ISmartRenameSessionFactoryWrapper.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Lightup/ISmartRenameSessionFactoryWrapper.cs rename to src/roslyn/src/EditorFeatures/Core/Lightup/ISmartRenameSessionFactoryWrapper.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Lightup/ISmartRenameSessionWrapper.cs b/src/roslyn/src/EditorFeatures/Core/Lightup/ISmartRenameSessionWrapper.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Lightup/ISmartRenameSessionWrapper.cs rename to src/roslyn/src/EditorFeatures/Core/Lightup/ISmartRenameSessionWrapper.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Lightup/LightupHelpers.cs b/src/roslyn/src/EditorFeatures/Core/Lightup/LightupHelpers.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Lightup/LightupHelpers.cs rename to src/roslyn/src/EditorFeatures/Core/Lightup/LightupHelpers.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorAdornmentManager.cs b/src/roslyn/src/EditorFeatures/Core/LineSeparators/LineSeparatorAdornmentManager.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorAdornmentManager.cs rename to src/roslyn/src/EditorFeatures/Core/LineSeparators/LineSeparatorAdornmentManager.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorAdornmentManagerProvider.cs b/src/roslyn/src/EditorFeatures/Core/LineSeparators/LineSeparatorAdornmentManagerProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorAdornmentManagerProvider.cs rename to src/roslyn/src/EditorFeatures/Core/LineSeparators/LineSeparatorAdornmentManagerProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTag.cs b/src/roslyn/src/EditorFeatures/Core/LineSeparators/LineSeparatorTag.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTag.cs rename to src/roslyn/src/EditorFeatures/Core/LineSeparators/LineSeparatorTag.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTaggerProvider.cs b/src/roslyn/src/EditorFeatures/Core/LineSeparators/LineSeparatorTaggerProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/LineSeparators/LineSeparatorTaggerProvider.cs rename to src/roslyn/src/EditorFeatures/Core/LineSeparators/LineSeparatorTaggerProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj b/src/roslyn/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj index afdb3c89aa4..446f242c0f5 100644 --- a/src/roslyn/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj +++ b/src/roslyn/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj @@ -1,13 +1,13 @@  - + Library Microsoft.CodeAnalysis - $(NetVS);netstandard2.0 + net472 + true true $(DefineConstants);EDITOR_FEATURES - full Microsoft.CodeAnalysis.EditorFeatures.Common @@ -19,19 +19,23 @@ - + - + + + + - + + @@ -41,7 +45,6 @@ - @@ -67,8 +70,10 @@ + + @@ -78,13 +83,14 @@ - + + - + @@ -98,6 +104,10 @@ + + true + MSBuild:_GenerateResxSource + @@ -106,4 +116,4 @@ - + \ No newline at end of file diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/NavigableSymbols/NavigableSymbolService.NavigableSymbol.cs b/src/roslyn/src/EditorFeatures/Core/NavigableSymbols/NavigableSymbolService.NavigableSymbol.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/NavigableSymbols/NavigableSymbolService.NavigableSymbol.cs rename to src/roslyn/src/EditorFeatures/Core/NavigableSymbols/NavigableSymbolService.NavigableSymbol.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/NavigableSymbols/NavigableSymbolService.NavigableSymbolSource.cs b/src/roslyn/src/EditorFeatures/Core/NavigableSymbols/NavigableSymbolService.NavigableSymbolSource.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/NavigableSymbols/NavigableSymbolService.NavigableSymbolSource.cs rename to src/roslyn/src/EditorFeatures/Core/NavigableSymbols/NavigableSymbolService.NavigableSymbolSource.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/NavigableSymbols/NavigableSymbolService.cs b/src/roslyn/src/EditorFeatures/Core/NavigableSymbols/NavigableSymbolService.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/NavigableSymbols/NavigableSymbolService.cs rename to src/roslyn/src/EditorFeatures/Core/NavigableSymbols/NavigableSymbolService.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/NavigateTo/DefaultNavigateToPreviewService.cs b/src/roslyn/src/EditorFeatures/Core/NavigateTo/DefaultNavigateToPreviewService.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/NavigateTo/DefaultNavigateToPreviewService.cs rename to src/roslyn/src/EditorFeatures/Core/NavigateTo/DefaultNavigateToPreviewService.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/NavigateTo/DefaultNavigateToPreviewServiceFactory.cs b/src/roslyn/src/EditorFeatures/Core/NavigateTo/DefaultNavigateToPreviewServiceFactory.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/NavigateTo/DefaultNavigateToPreviewServiceFactory.cs rename to src/roslyn/src/EditorFeatures/Core/NavigateTo/DefaultNavigateToPreviewServiceFactory.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/NavigateTo/INavigateToPreviewService.cs b/src/roslyn/src/EditorFeatures/Core/NavigateTo/INavigateToPreviewService.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/NavigateTo/INavigateToPreviewService.cs rename to src/roslyn/src/EditorFeatures/Core/NavigateTo/INavigateToPreviewService.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemDisplay.cs b/src/roslyn/src/EditorFeatures/Core/NavigateTo/NavigateToItemDisplay.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemDisplay.cs rename to src/roslyn/src/EditorFeatures/Core/NavigateTo/NavigateToItemDisplay.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemDisplayFactory.cs b/src/roslyn/src/EditorFeatures/Core/NavigateTo/NavigateToItemDisplayFactory.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemDisplayFactory.cs rename to src/roslyn/src/EditorFeatures/Core/NavigateTo/NavigateToItemDisplayFactory.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.Callback.cs b/src/roslyn/src/EditorFeatures/Core/NavigateTo/NavigateToItemProvider.Callback.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.Callback.cs rename to src/roslyn/src/EditorFeatures/Core/NavigateTo/NavigateToItemProvider.Callback.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.cs b/src/roslyn/src/EditorFeatures/Core/NavigateTo/NavigateToItemProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.cs rename to src/roslyn/src/EditorFeatures/Core/NavigateTo/NavigateToItemProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Notification/EditorNotificationServiceFactory.cs b/src/roslyn/src/EditorFeatures/Core/Notification/EditorNotificationServiceFactory.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Notification/EditorNotificationServiceFactory.cs rename to src/roslyn/src/EditorFeatures/Core/Notification/EditorNotificationServiceFactory.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Peek/DefinitionPeekableItem.cs b/src/roslyn/src/EditorFeatures/Core/Peek/DefinitionPeekableItem.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Peek/DefinitionPeekableItem.cs rename to src/roslyn/src/EditorFeatures/Core/Peek/DefinitionPeekableItem.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Peek/ExternalFilePeekableItem.cs b/src/roslyn/src/EditorFeatures/Core/Peek/ExternalFilePeekableItem.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Peek/ExternalFilePeekableItem.cs rename to src/roslyn/src/EditorFeatures/Core/Peek/ExternalFilePeekableItem.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Peek/PeekHelpers.cs b/src/roslyn/src/EditorFeatures/Core/Peek/PeekHelpers.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Peek/PeekHelpers.cs rename to src/roslyn/src/EditorFeatures/Core/Peek/PeekHelpers.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Peek/PeekableItem.cs b/src/roslyn/src/EditorFeatures/Core/Peek/PeekableItem.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Peek/PeekableItem.cs rename to src/roslyn/src/EditorFeatures/Core/Peek/PeekableItem.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Peek/PeekableItemFactory.cs b/src/roslyn/src/EditorFeatures/Core/Peek/PeekableItemFactory.cs similarity index 96% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Peek/PeekableItemFactory.cs rename to src/roslyn/src/EditorFeatures/Core/Peek/PeekableItemFactory.cs index b26062e8216..f8f23606067 100644 --- a/src/roslyn/src/EditorFeatures/Core.Wpf/Peek/PeekableItemFactory.cs +++ b/src/roslyn/src/EditorFeatures/Core/Peek/PeekableItemFactory.cs @@ -10,7 +10,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.Peek; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.FindUsages; @@ -24,8 +23,8 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.Peek; -[Export(typeof(IPeekableItemFactory))] -internal sealed class PeekableItemFactory : IPeekableItemFactory +[Export] +internal class PeekableItemFactory { private readonly IMetadataAsSourceFileService _metadataAsSourceFileService; private readonly IGlobalOptionService _globalOptions; diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Peek/PeekableItemSource.cs b/src/roslyn/src/EditorFeatures/Core/Peek/PeekableItemSource.cs similarity index 97% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Peek/PeekableItemSource.cs rename to src/roslyn/src/EditorFeatures/Core/Peek/PeekableItemSource.cs index 719ff5d8816..25e74cfbde1 100644 --- a/src/roslyn/src/EditorFeatures/Core.Wpf/Peek/PeekableItemSource.cs +++ b/src/roslyn/src/EditorFeatures/Core/Peek/PeekableItemSource.cs @@ -7,7 +7,6 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.Peek; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Navigation; @@ -24,14 +23,14 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.Peek; internal sealed class PeekableItemSource : IPeekableItemSource { private readonly ITextBuffer _textBuffer; - private readonly IPeekableItemFactory _peekableItemFactory; + private readonly PeekableItemFactory _peekableItemFactory; private readonly IPeekResultFactory _peekResultFactory; private readonly IThreadingContext _threadingContext; private readonly IUIThreadOperationExecutor _uiThreadOperationExecutor; public PeekableItemSource( ITextBuffer textBuffer, - IPeekableItemFactory peekableItemFactory, + PeekableItemFactory peekableItemFactory, IPeekResultFactory peekResultFactory, IThreadingContext threadingContext, IUIThreadOperationExecutor uiThreadOperationExecutor) diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Peek/PeekableItemSourceProvider.cs b/src/roslyn/src/EditorFeatures/Core/Peek/PeekableItemSourceProvider.cs similarity index 88% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Peek/PeekableItemSourceProvider.cs rename to src/roslyn/src/EditorFeatures/Core/Peek/PeekableItemSourceProvider.cs index 9f4908ca351..85421305f49 100644 --- a/src/roslyn/src/EditorFeatures/Core.Wpf/Peek/PeekableItemSourceProvider.cs +++ b/src/roslyn/src/EditorFeatures/Core/Peek/PeekableItemSourceProvider.cs @@ -4,7 +4,6 @@ using System; using System.ComponentModel.Composition; -using Microsoft.CodeAnalysis.Editor.Peek; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.VisualStudio.Language.Intellisense; @@ -20,7 +19,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.Peek; [SupportsPeekRelationship("IsDefinedBy")] internal sealed class PeekableItemSourceProvider : IPeekableItemSourceProvider { - private readonly IPeekableItemFactory _peekableItemFactory; + private readonly PeekableItemFactory _peekableItemFactory; private readonly IPeekResultFactory _peekResultFactory; private readonly IThreadingContext _threadingContext; private readonly IUIThreadOperationExecutor _uiThreadOperationExecutor; @@ -28,7 +27,7 @@ internal sealed class PeekableItemSourceProvider : IPeekableItemSourceProvider [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public PeekableItemSourceProvider( - IPeekableItemFactory peekableItemFactory, + PeekableItemFactory peekableItemFactory, IPeekResultFactory peekResultFactory, IThreadingContext threadingContext, IUIThreadOperationExecutor uiThreadOperationExecutor) @@ -39,7 +38,7 @@ public PeekableItemSourceProvider( _uiThreadOperationExecutor = uiThreadOperationExecutor; } - public IPeekableItemSource TryCreatePeekableItemSource(ITextBuffer textBuffer) + public IPeekableItemSource? TryCreatePeekableItemSource(ITextBuffer textBuffer) => textBuffer.Properties.GetOrCreateSingletonProperty(() => new PeekableItemSource(textBuffer, _peekableItemFactory, _peekResultFactory, _threadingContext, _uiThreadOperationExecutor)); } diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Preview/AbstractPreviewTaggerProvider.cs b/src/roslyn/src/EditorFeatures/Core/Preview/AbstractPreviewTaggerProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Preview/AbstractPreviewTaggerProvider.cs rename to src/roslyn/src/EditorFeatures/Core/Preview/AbstractPreviewTaggerProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Preview/DifferenceViewerPreview.NavigationalCommandTarget.cs b/src/roslyn/src/EditorFeatures/Core/Preview/DifferenceViewerPreview.NavigationalCommandTarget.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Preview/DifferenceViewerPreview.NavigationalCommandTarget.cs rename to src/roslyn/src/EditorFeatures/Core/Preview/DifferenceViewerPreview.NavigationalCommandTarget.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Preview/DifferenceViewerPreview.cs b/src/roslyn/src/EditorFeatures/Core/Preview/DifferenceViewerPreview.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Preview/DifferenceViewerPreview.cs rename to src/roslyn/src/EditorFeatures/Core/Preview/DifferenceViewerPreview.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Preview/PreviewConflictViewTaggerProvider.cs b/src/roslyn/src/EditorFeatures/Core/Preview/PreviewConflictViewTaggerProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Preview/PreviewConflictViewTaggerProvider.cs rename to src/roslyn/src/EditorFeatures/Core/Preview/PreviewConflictViewTaggerProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Preview/PreviewFactoryService.cs b/src/roslyn/src/EditorFeatures/Core/Preview/PreviewFactoryService.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Preview/PreviewFactoryService.cs rename to src/roslyn/src/EditorFeatures/Core/Preview/PreviewFactoryService.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Preview/PreviewReferenceHighlightingTaggerProvider.cs b/src/roslyn/src/EditorFeatures/Core/Preview/PreviewReferenceHighlightingTaggerProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Preview/PreviewReferenceHighlightingTaggerProvider.cs rename to src/roslyn/src/EditorFeatures/Core/Preview/PreviewReferenceHighlightingTaggerProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Preview/PreviewStaticClassificationTaggerProvider.cs b/src/roslyn/src/EditorFeatures/Core/Preview/PreviewStaticClassificationTaggerProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Preview/PreviewStaticClassificationTaggerProvider.cs rename to src/roslyn/src/EditorFeatures/Core/Preview/PreviewStaticClassificationTaggerProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Preview/PreviewWarningViewTaggerProvider.cs b/src/roslyn/src/EditorFeatures/Core/Preview/PreviewWarningViewTaggerProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Preview/PreviewWarningViewTaggerProvider.cs rename to src/roslyn/src/EditorFeatures/Core/Preview/PreviewWarningViewTaggerProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/PreviewWarningTagDefinition.cs b/src/roslyn/src/EditorFeatures/Core/PreviewWarningTagDefinition.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/PreviewWarningTagDefinition.cs rename to src/roslyn/src/EditorFeatures/Core/PreviewWarningTagDefinition.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/ClassificationFormatDefinitions.cs b/src/roslyn/src/EditorFeatures/Core/QuickInfo/ClassificationFormatDefinitions.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/ClassificationFormatDefinitions.cs rename to src/roslyn/src/EditorFeatures/Core/QuickInfo/ClassificationFormatDefinitions.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/ContentControlService.cs b/src/roslyn/src/EditorFeatures/Core/QuickInfo/ContentControlService.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/ContentControlService.cs rename to src/roslyn/src/EditorFeatures/Core/QuickInfo/ContentControlService.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/DisposableToolTip.cs b/src/roslyn/src/EditorFeatures/Core/QuickInfo/DisposableToolTip.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/DisposableToolTip.cs rename to src/roslyn/src/EditorFeatures/Core/QuickInfo/DisposableToolTip.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/Extensions.cs b/src/roslyn/src/EditorFeatures/Core/QuickInfo/Extensions.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/Extensions.cs rename to src/roslyn/src/EditorFeatures/Core/QuickInfo/Extensions.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/IContentControlService.cs b/src/roslyn/src/EditorFeatures/Core/QuickInfo/IContentControlService.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/IContentControlService.cs rename to src/roslyn/src/EditorFeatures/Core/QuickInfo/IContentControlService.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/LazyToolTip.cs b/src/roslyn/src/EditorFeatures/Core/QuickInfo/LazyToolTip.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/LazyToolTip.cs rename to src/roslyn/src/EditorFeatures/Core/QuickInfo/LazyToolTip.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsState.cs b/src/roslyn/src/EditorFeatures/Core/QuickInfo/OnTheFlyDocsState.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsState.cs rename to src/roslyn/src/EditorFeatures/Core/QuickInfo/OnTheFlyDocsState.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsView.xaml b/src/roslyn/src/EditorFeatures/Core/QuickInfo/OnTheFlyDocsView.xaml similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsView.xaml rename to src/roslyn/src/EditorFeatures/Core/QuickInfo/OnTheFlyDocsView.xaml diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsView.xaml.cs b/src/roslyn/src/EditorFeatures/Core/QuickInfo/OnTheFlyDocsView.xaml.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsView.xaml.cs rename to src/roslyn/src/EditorFeatures/Core/QuickInfo/OnTheFlyDocsView.xaml.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsViewFactory.cs b/src/roslyn/src/EditorFeatures/Core/QuickInfo/OnTheFlyDocsViewFactory.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsViewFactory.cs rename to src/roslyn/src/EditorFeatures/Core/QuickInfo/OnTheFlyDocsViewFactory.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsViewStateVisibilityConverter.cs b/src/roslyn/src/EditorFeatures/Core/QuickInfo/OnTheFlyDocsViewStateVisibilityConverter.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/OnTheFlyDocsViewStateVisibilityConverter.cs rename to src/roslyn/src/EditorFeatures/Core/QuickInfo/OnTheFlyDocsViewStateVisibilityConverter.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/ProjectionBufferContent.cs b/src/roslyn/src/EditorFeatures/Core/QuickInfo/ProjectionBufferContent.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/QuickInfo/ProjectionBufferContent.cs rename to src/roslyn/src/EditorFeatures/Core/QuickInfo/ProjectionBufferContent.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/ReferenceHighlighting/DefinitionHighlightTagDefinition.cs b/src/roslyn/src/EditorFeatures/Core/ReferenceHighlighting/DefinitionHighlightTagDefinition.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/ReferenceHighlighting/DefinitionHighlightTagDefinition.cs rename to src/roslyn/src/EditorFeatures/Core/ReferenceHighlighting/DefinitionHighlightTagDefinition.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/ReferenceHighlighting/WrittenReferenceHighlightTagDefinition.cs b/src/roslyn/src/EditorFeatures/Core/ReferenceHighlighting/WrittenReferenceHighlightTagDefinition.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/ReferenceHighlighting/WrittenReferenceHighlightTagDefinition.cs rename to src/roslyn/src/EditorFeatures/Core/ReferenceHighlighting/WrittenReferenceHighlightTagDefinition.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/RenameTracking/RenameTrackingTagDefinition.cs b/src/roslyn/src/EditorFeatures/Core/RenameTracking/RenameTrackingTagDefinition.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/RenameTracking/RenameTrackingTagDefinition.cs rename to src/roslyn/src/EditorFeatures/Core/RenameTracking/RenameTrackingTagDefinition.cs diff --git a/src/roslyn/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.ViewSpanChangedEventSource.cs b/src/roslyn/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.ViewSpanChangedEventSource.cs index a238effe8b3..650555e802b 100644 --- a/src/roslyn/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.ViewSpanChangedEventSource.cs +++ b/src/roslyn/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.ViewSpanChangedEventSource.cs @@ -21,7 +21,6 @@ private sealed class ViewSpanChangedEventSource : AbstractTaggerEventSource public ViewSpanChangedEventSource(IThreadingContext threadingContext, ITextView textView) { - Debug.Assert(textView != null); _threadingContext = threadingContext; _textView = textView; } diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/AbstractSignatureHelpCommandHandler.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/AbstractSignatureHelpCommandHandler.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/AbstractSignatureHelpCommandHandler.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/AbstractSignatureHelpCommandHandler.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/Controller.Session.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/Controller.Session.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/Controller.Session_ComputeModel.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_ComputeModel.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/Controller.Session_ComputeModel.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_SetModelSelectedItem.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/Controller.Session_SetModelSelectedItem.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_SetModelSelectedItem.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/Controller.Session_SetModelSelectedItem.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_UpdateModel.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/Controller.Session_UpdateModel.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.Session_UpdateModel.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/Controller.Session_UpdateModel.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/Controller.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/Controller.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_InvokeSignatureHelp.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/Controller_InvokeSignatureHelp.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_InvokeSignatureHelp.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/Controller_InvokeSignatureHelp.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_OnCaretPositionChanged.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/Controller_OnCaretPositionChanged.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_OnCaretPositionChanged.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/Controller_OnCaretPositionChanged.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_OnTextViewBufferPostChanged.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/Controller_OnTextViewBufferPostChanged.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_OnTextViewBufferPostChanged.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/Controller_OnTextViewBufferPostChanged.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_TypeChar.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/Controller_TypeChar.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Controller_TypeChar.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/Controller_TypeChar.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Model.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/Model.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Model.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/Model.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/ModelUpdatedEventsArgs.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/ModelUpdatedEventsArgs.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/ModelUpdatedEventsArgs.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/ModelUpdatedEventsArgs.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/Parameter.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/Presentation/Parameter.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/Parameter.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/Presentation/Parameter.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/Signature.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/Presentation/Signature.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/Signature.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/Presentation/Signature.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/SignatureHelpClassifier.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/Presentation/SignatureHelpClassifier.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/SignatureHelpClassifier.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/Presentation/SignatureHelpClassifier.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/SignatureHelpClassifierProvider.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/Presentation/SignatureHelpClassifierProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/SignatureHelpClassifierProvider.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/Presentation/SignatureHelpClassifierProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/SignatureHelpPresenter.SignatureHelpPresenterSession.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/Presentation/SignatureHelpPresenter.SignatureHelpPresenterSession.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/SignatureHelpPresenter.SignatureHelpPresenterSession.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/Presentation/SignatureHelpPresenter.SignatureHelpPresenterSession.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/SignatureHelpPresenter.SignatureHelpSource.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/Presentation/SignatureHelpPresenter.SignatureHelpSource.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/SignatureHelpPresenter.SignatureHelpSource.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/Presentation/SignatureHelpPresenter.SignatureHelpSource.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/SignatureHelpPresenter.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/Presentation/SignatureHelpPresenter.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/Presentation/SignatureHelpPresenter.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/Presentation/SignatureHelpPresenter.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/SignatureHelpBeforeCompletionCommandHandler.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/SignatureHelpBeforeCompletionCommandHandler.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/SignatureHelpBeforeCompletionCommandHandler.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/SignatureHelpBeforeCompletionCommandHandler.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/SignatureHelpControllerProvider.cs b/src/roslyn/src/EditorFeatures/Core/SignatureHelp/SignatureHelpControllerProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/SignatureHelp/SignatureHelpControllerProvider.cs rename to src/roslyn/src/EditorFeatures/Core/SignatureHelp/SignatureHelpControllerProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/StringCopyPaste/WpfStringCopyPasteService.cs b/src/roslyn/src/EditorFeatures/Core/StringCopyPaste/WpfStringCopyPasteService.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/StringCopyPaste/WpfStringCopyPasteService.cs rename to src/roslyn/src/EditorFeatures/Core/StringCopyPaste/WpfStringCopyPasteService.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationAdornmentManager.VisibleBlock.cs b/src/roslyn/src/EditorFeatures/Core/StringIndentation/StringIndentationAdornmentManager.VisibleBlock.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationAdornmentManager.VisibleBlock.cs rename to src/roslyn/src/EditorFeatures/Core/StringIndentation/StringIndentationAdornmentManager.VisibleBlock.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationAdornmentManager.cs b/src/roslyn/src/EditorFeatures/Core/StringIndentation/StringIndentationAdornmentManager.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationAdornmentManager.cs rename to src/roslyn/src/EditorFeatures/Core/StringIndentation/StringIndentationAdornmentManager.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationAdornmentManagerProvider.cs b/src/roslyn/src/EditorFeatures/Core/StringIndentation/StringIndentationAdornmentManagerProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationAdornmentManagerProvider.cs rename to src/roslyn/src/EditorFeatures/Core/StringIndentation/StringIndentationAdornmentManagerProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationTag.cs b/src/roslyn/src/EditorFeatures/Core/StringIndentation/StringIndentationTag.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationTag.cs rename to src/roslyn/src/EditorFeatures/Core/StringIndentation/StringIndentationTag.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationTaggerProvider.cs b/src/roslyn/src/EditorFeatures/Core/StringIndentation/StringIndentationTaggerProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/StringIndentation/StringIndentationTaggerProvider.cs rename to src/roslyn/src/EditorFeatures/Core/StringIndentation/StringIndentationTaggerProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Structure/StructureTaggerProvider.cs b/src/roslyn/src/EditorFeatures/Core/Structure/StructureTaggerProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Structure/StructureTaggerProvider.cs rename to src/roslyn/src/EditorFeatures/Core/Structure/StructureTaggerProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/Copilot/FlavoredSuggestedAction.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/Copilot/FlavoredSuggestedAction.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/Copilot/FlavoredSuggestedAction.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/Copilot/FlavoredSuggestedAction.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/FixAll/FixAllGetFixesService.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/FixAll/FixAllGetFixesService.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/FixAll/FixAllGetFixesService.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/FixAll/FixAllGetFixesService.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/FixAll/FixMultipleOccurrencesService.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/FixAll/FixMultipleOccurrencesService.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/FixAll/FixMultipleOccurrencesService.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/FixAll/FixMultipleOccurrencesService.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/PreviewChanges/PreviewChangesCodeAction.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/PreviewChanges/PreviewChangesCodeAction.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/PreviewChanges/PreviewChangesCodeAction.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/PreviewChanges/PreviewChangesCodeAction.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/PreviewChanges/PreviewChangesSuggestedAction.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/PreviewChanges/PreviewChangesSuggestedAction.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/PreviewChanges/PreviewChangesSuggestedAction.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/PreviewChanges/PreviewChangesSuggestedAction.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/RefineUsingCopilot/RefineUsingCopilotCodeAction.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/RefineUsingCopilot/RefineUsingCopilotCodeAction.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/RefineUsingCopilot/RefineUsingCopilotCodeAction.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/RefineUsingCopilot/RefineUsingCopilotCodeAction.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/RefineUsingCopilot/RefineUsingCopilotSuggestedAction.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/RefineUsingCopilot/RefineUsingCopilotSuggestedAction.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/RefineUsingCopilot/RefineUsingCopilotSuggestedAction.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/RefineUsingCopilot/RefineUsingCopilotSuggestedAction.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionPriorityProvider.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActionPriorityProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionPriorityProvider.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActionPriorityProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedActions.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActionWithNestedActions.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedActions.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActionWithNestedActions.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedFlavors.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActionWithNestedFlavors.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionWithNestedFlavors.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActionWithNestedFlavors.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/AbstractFixAllSuggestedAction.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActions/AbstractFixAllSuggestedAction.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/AbstractFixAllSuggestedAction.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActions/AbstractFixAllSuggestedAction.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/CodeFixSuggestedAction.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActions/CodeFixSuggestedAction.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/CodeFixSuggestedAction.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActions/CodeFixSuggestedAction.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/CodeRefactoringSuggestedAction.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActions/CodeRefactoringSuggestedAction.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/CodeRefactoringSuggestedAction.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActions/CodeRefactoringSuggestedAction.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeFixSuggestedAction.FixAllCodeAction.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActions/FixAllCodeFixSuggestedAction.FixAllCodeAction.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeFixSuggestedAction.FixAllCodeAction.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActions/FixAllCodeFixSuggestedAction.FixAllCodeAction.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeFixSuggestedAction.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActions/FixAllCodeFixSuggestedAction.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeFixSuggestedAction.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActions/FixAllCodeFixSuggestedAction.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeRefactoringSuggestedAction.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActions/FixAllCodeRefactoringSuggestedAction.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/FixAllCodeRefactoringSuggestedAction.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActions/FixAllCodeRefactoringSuggestedAction.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.CaretPositionRestorer.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActions/SuggestedAction.CaretPositionRestorer.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.CaretPositionRestorer.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActions/SuggestedAction.CaretPositionRestorer.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActions/SuggestedAction.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActions/SuggestedAction.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActions/SuggestedAction.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.State.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActionsSource.State.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.State.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActionsSource.State.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActionsSource.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActionsSource.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.EditorOption.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActionsSourceProvider.EditorOption.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.EditorOption.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActionsSourceProvider.EditorOption.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActionsSourceProvider.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSourceProvider.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActionsSourceProvider.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource_Async.cs b/src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActionsSource_Async.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionsSource_Async.cs rename to src/roslyn/src/EditorFeatures/Core/Suggestions/SuggestedActionsSource_Async.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Tagging/EditorFormatMapChangedEventSource.cs b/src/roslyn/src/EditorFeatures/Core/Tagging/EditorFormatMapChangedEventSource.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Tagging/EditorFormatMapChangedEventSource.cs rename to src/roslyn/src/EditorFeatures/Core/Tagging/EditorFormatMapChangedEventSource.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Tags/DefaultImageIdService.cs b/src/roslyn/src/EditorFeatures/Core/Tags/DefaultImageIdService.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Tags/DefaultImageIdService.cs rename to src/roslyn/src/EditorFeatures/Core/Tags/DefaultImageIdService.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Utilities/BrushToColorConverter.cs b/src/roslyn/src/EditorFeatures/Core/Utilities/BrushToColorConverter.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Utilities/BrushToColorConverter.cs rename to src/roslyn/src/EditorFeatures/Core/Utilities/BrushToColorConverter.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Utilities/NativeMethods.cs b/src/roslyn/src/EditorFeatures/Core/Utilities/NativeMethods.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Utilities/NativeMethods.cs rename to src/roslyn/src/EditorFeatures/Core/Utilities/NativeMethods.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Utilities/RoslynServiceExtensions.cs b/src/roslyn/src/EditorFeatures/Core/Utilities/RoslynServiceExtensions.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Utilities/RoslynServiceExtensions.cs rename to src/roslyn/src/EditorFeatures/Core/Utilities/RoslynServiceExtensions.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/ViewHostingControl.cs b/src/roslyn/src/EditorFeatures/Core/ViewHostingControl.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/ViewHostingControl.cs rename to src/roslyn/src/EditorFeatures/Core/ViewHostingControl.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/Workspaces/WpfTextBufferVisibilityTracker.cs b/src/roslyn/src/EditorFeatures/Core/Workspaces/WpfTextBufferVisibilityTracker.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/Workspaces/WpfTextBufferVisibilityTracker.cs rename to src/roslyn/src/EditorFeatures/Core/Workspaces/WpfTextBufferVisibilityTracker.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/WpfClassificationExtensions.cs b/src/roslyn/src/EditorFeatures/Core/WpfClassificationExtensions.cs similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/WpfClassificationExtensions.cs rename to src/roslyn/src/EditorFeatures/Core/WpfClassificationExtensions.cs diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.cs.xlf b/src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.cs.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.cs.xlf rename to src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.cs.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.de.xlf b/src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.de.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.de.xlf rename to src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.de.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.es.xlf b/src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.es.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.es.xlf rename to src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.es.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.fr.xlf b/src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.fr.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.fr.xlf rename to src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.fr.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.it.xlf b/src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.it.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.it.xlf rename to src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.it.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.ja.xlf b/src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.ja.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.ja.xlf rename to src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.ja.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.ko.xlf b/src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.ko.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.ko.xlf rename to src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.ko.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.pl.xlf b/src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.pl.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.pl.xlf rename to src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.pl.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.pt-BR.xlf b/src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.pt-BR.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.pt-BR.xlf rename to src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.pt-BR.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.ru.xlf b/src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.ru.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.ru.xlf rename to src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.ru.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.tr.xlf b/src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.tr.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.tr.xlf rename to src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.tr.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.zh-Hans.xlf b/src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.zh-Hans.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.zh-Hans.xlf rename to src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.zh-Hans.xlf diff --git a/src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.zh-Hant.xlf b/src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.zh-Hant.xlf similarity index 100% rename from src/roslyn/src/EditorFeatures/Core.Wpf/xlf/EditorFeaturesWpfResources.zh-Hant.xlf rename to src/roslyn/src/EditorFeatures/Core/xlf/EditorFeaturesWpfResources.zh-Hant.xlf diff --git a/src/roslyn/src/EditorFeatures/ExternalAccess/Debugger/Microsoft.CodeAnalysis.ExternalAccess.Debugger.csproj b/src/roslyn/src/EditorFeatures/ExternalAccess/Debugger/Microsoft.CodeAnalysis.ExternalAccess.Debugger.csproj index 7878cd661cc..abb7fff6557 100644 --- a/src/roslyn/src/EditorFeatures/ExternalAccess/Debugger/Microsoft.CodeAnalysis.ExternalAccess.Debugger.csproj +++ b/src/roslyn/src/EditorFeatures/ExternalAccess/Debugger/Microsoft.CodeAnalysis.ExternalAccess.Debugger.csproj @@ -1,10 +1,11 @@  - + Library Microsoft.CodeAnalysis.ExternalAccess.Debugger - netstandard2.0 + net472 + true true @@ -38,4 +39,4 @@ - + \ No newline at end of file diff --git a/src/roslyn/src/EditorFeatures/Test2/Peek/PeekTests.vb b/src/roslyn/src/EditorFeatures/Test2/Peek/PeekTests.vb index fe764dd1a3e..93223ec8566 100644 --- a/src/roslyn/src/EditorFeatures/Test2/Peek/PeekTests.vb +++ b/src/roslyn/src/EditorFeatures/Test2/Peek/PeekTests.vb @@ -308,11 +308,12 @@ public partial class D Dim textBuffer = document.GetTextBuffer() Dim textView = document.GetTextView() - Dim peekableItemSource As New PeekableItemSource(textBuffer, - workspace.GetService(Of IPeekableItemFactory), - New MockPeekResultFactory(workspace.GetService(Of IPersistentSpanFactory)), - workspace.GetService(Of IThreadingContext), - workspace.GetService(Of IUIThreadOperationExecutor)) + Dim peekableItemSource As New PeekableItemSource( + textBuffer, + workspace.GetService(Of PeekableItemFactory), + New MockPeekResultFactory(workspace.GetService(Of IPersistentSpanFactory)), + workspace.GetService(Of IThreadingContext), + workspace.GetService(Of IUIThreadOperationExecutor)) Dim peekableSession As New Mock(Of IPeekSession)(MockBehavior.Strict) Dim triggerPoint = New SnapshotPoint(document.GetTextBuffer().CurrentSnapshot, document.CursorPosition.Value) diff --git a/src/roslyn/src/EditorFeatures/VisualBasic/Microsoft.CodeAnalysis.VisualBasic.EditorFeatures.vbproj b/src/roslyn/src/EditorFeatures/VisualBasic/Microsoft.CodeAnalysis.VisualBasic.EditorFeatures.vbproj index e823fb16776..f404138468d 100644 --- a/src/roslyn/src/EditorFeatures/VisualBasic/Microsoft.CodeAnalysis.VisualBasic.EditorFeatures.vbproj +++ b/src/roslyn/src/EditorFeatures/VisualBasic/Microsoft.CodeAnalysis.VisualBasic.EditorFeatures.vbproj @@ -1,11 +1,11 @@  - + Library - $(NetVS);netstandard2.0 - full + true + net472 true diff --git a/src/roslyn/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SymbolCompletionProviderTests.vb b/src/roslyn/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SymbolCompletionProviderTests.vb index 3068843e732..f0bf1e3d872 100644 --- a/src/roslyn/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SymbolCompletionProviderTests.vb +++ b/src/roslyn/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/SymbolCompletionProviderTests.vb @@ -5640,7 +5640,7 @@ Class C .ToString().NormalizeLineEndings() - Dim expectedDescription = $"({FeaturesResources.field}) C.x As Integer" + vbCrLf + vbCrLf + String.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available) + vbCrLf + String.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available) + vbCrLf + vbCrLf + FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts + Dim expectedDescription = $"({FeaturesResources.field}) C.x As Integer" + vbCrLf + vbCrLf + " " + String.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available) + vbCrLf + " " + String.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available) + vbCrLf + vbCrLf + FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts Await VerifyItemInLinkedFilesAsync(markup, "x", expectedDescription) End Function diff --git a/src/roslyn/src/EditorFeatures/VisualBasicTest/SignatureHelp/InvocationExpressionSignatureHelpProviderTests.vb b/src/roslyn/src/EditorFeatures/VisualBasicTest/SignatureHelp/InvocationExpressionSignatureHelpProviderTests.vb index 605f26560e5..8cb4b7cd813 100644 --- a/src/roslyn/src/EditorFeatures/VisualBasicTest/SignatureHelp/InvocationExpressionSignatureHelpProviderTests.vb +++ b/src/roslyn/src/EditorFeatures/VisualBasicTest/SignatureHelp/InvocationExpressionSignatureHelpProviderTests.vb @@ -1822,7 +1822,7 @@ end class ]]>.Value.NormalizeLineEndings() - Dim expectedDescription = New SignatureHelpTestItem("C.bar()" + vbCrLf + vbCrLf + String.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available) + vbCrLf + String.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available) + vbCrLf + vbCrLf + FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts, currentParameterIndex:=0) + Dim expectedDescription = New SignatureHelpTestItem("C.bar()" + vbCrLf + vbCrLf + " " + String.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available) + vbCrLf + " " + String.Format(FeaturesResources._0_1, "Proj2", FeaturesResources.Not_Available) + vbCrLf + vbCrLf + FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts, currentParameterIndex:=0) Await VerifyItemWithReferenceWorkerAsync(markup, {expectedDescription}, False) End Function @@ -1852,7 +1852,7 @@ class C ]]>.Value.NormalizeLineEndings() - Dim expectedDescription = New SignatureHelpTestItem("C.bar()" + $"\r\n\r\n{String.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n{String.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}".Replace("\r\n", vbCrLf), currentParameterIndex:=0) + Dim expectedDescription = New SignatureHelpTestItem("C.bar()" + $"\r\n\r\n {String.Format(FeaturesResources._0_1, "Proj1", FeaturesResources.Available)}\r\n {String.Format(FeaturesResources._0_1, "Proj3", FeaturesResources.Not_Available)}\r\n\r\n{FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts}".Replace("\r\n", vbCrLf), currentParameterIndex:=0) Await VerifyItemWithReferenceWorkerAsync(markup, {expectedDescription}, False) End Function diff --git a/src/roslyn/src/Features/Core/Portable/FeaturesResources.resx b/src/roslyn/src/Features/Core/Portable/FeaturesResources.resx index 066a34a11f9..1521e7452b3 100644 --- a/src/roslyn/src/Features/Core/Portable/FeaturesResources.resx +++ b/src/roslyn/src/Features/Core/Portable/FeaturesResources.resx @@ -566,7 +566,7 @@ Do you want to continue? Not Available ⚠ - {0} - {1} + {0} - {1} You can use the navigation bar to switch contexts. diff --git a/src/roslyn/src/Features/Core/Portable/Shared/Utilities/SupportedPlatformData.cs b/src/roslyn/src/Features/Core/Portable/Shared/Utilities/SupportedPlatformData.cs index eaee2a11be5..9e94a119520 100644 --- a/src/roslyn/src/Features/Core/Portable/Shared/Utilities/SupportedPlatformData.cs +++ b/src/roslyn/src/Features/Core/Portable/Shared/Utilities/SupportedPlatformData.cs @@ -31,6 +31,7 @@ public IList ToDisplayParts() foreach (var project in projects) { var text = string.Format(FeaturesResources._0_1, project.Name, Supported(!InvalidProjects.Contains(project.Id))); + builder.AddSpace(" "); builder.AddText(text); builder.AddLineBreak(); } diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf index a85fbec6a7f..14838d2f49a 100644 --- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf +++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf @@ -4191,8 +4191,8 @@ Chcete pokračovat? - {0} - {1} - {0} – {1} + {0} - {1} + {0} – {1} diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf index c5b55914d74..8fe80d9447f 100644 --- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf +++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf @@ -4191,8 +4191,8 @@ Möchten Sie fortfahren? - {0} - {1} - {0} - {1} + {0} - {1} + {0} - {1} diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf index 2bd7b801d8a..5a91d8d92f2 100644 --- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf +++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf @@ -4191,8 +4191,8 @@ Do you want to continue? - {0} - {1} - {0} - {1} + {0} - {1} + {0} - {1} diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf index 7f6d49f69e9..0412ea66971 100644 --- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf +++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf @@ -4191,8 +4191,8 @@ Voulez-vous continuer ? - {0} - {1} - {0} - {1} + {0} - {1} + {0} - {1} diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf index bbcee6f9e0a..3fc4da01a44 100644 --- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf +++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf @@ -4191,8 +4191,8 @@ Continuare? - {0} - {1} - {0} - {1} + {0} - {1} + {0} - {1} diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf index 47012f23fdf..0cfd33e4874 100644 --- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf +++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf @@ -4191,8 +4191,8 @@ Do you want to continue? - {0} - {1} - {0} - {1} + {0} - {1} + {0} - {1} diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf index 93b3d49dedc..b5e232d5567 100644 --- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf +++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf @@ -4191,8 +4191,8 @@ Do you want to continue? - {0} - {1} - {0} - {1} + {0} - {1} + {0} - {1} diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf index 881676ab794..8124779fdb2 100644 --- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf +++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf @@ -4191,8 +4191,8 @@ Czy chcesz kontynuować? - {0} - {1} - {0} - {1} + {0} - {1} + {0} - {1} diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf index 9c0a0cd9d26..15e3df911f2 100644 --- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf +++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf @@ -4191,8 +4191,8 @@ Deseja continuar? - {0} - {1} - {0} - {1} + {0} - {1} + {0} - {1} diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf index 32f029cd006..4ad9277a355 100644 --- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf +++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf @@ -4191,8 +4191,8 @@ Do you want to continue? - {0} - {1} - {0} - {1} + {0} - {1} + {0} - {1} diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf index 7ef132b4e25..a828b6232fd 100644 --- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf +++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf @@ -4191,8 +4191,8 @@ Devam etmek istiyor musunuz? - {0} - {1} - {0} - {1} + {0} - {1} + {0} - {1} diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf index fcb80a1240a..a84e76e3f89 100644 --- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf +++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf @@ -4191,8 +4191,8 @@ Do you want to continue? - {0} - {1} - {0} - {1} + {0} - {1} + {0} - {1} diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf index c70ecd1cdcc..bf54961621c 100644 --- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf +++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf @@ -4191,8 +4191,8 @@ Do you want to continue? - {0} - {1} - {0} - {1} + {0} - {1} + {0} - {1} diff --git a/src/roslyn/src/LanguageServer/Protocol/RoslynLanguageServer.cs b/src/roslyn/src/LanguageServer/Protocol/RoslynLanguageServer.cs index 8d11be7d6c2..773867a2089 100644 --- a/src/roslyn/src/LanguageServer/Protocol/RoslynLanguageServer.cs +++ b/src/roslyn/src/LanguageServer/Protocol/RoslynLanguageServer.cs @@ -98,7 +98,7 @@ private FrozenDictionary> GetBaseServices( // those cases, we do not need to add an additional workspace to manage new files we hear about. So only // add the LspMiscellaneousFilesWorkspace for hosts that have not already brought their own. if (serverKind == WellKnownLspServerKinds.CSharpVisualBasicLspServer) - AddLazyService(lspServices => lspServices.GetRequiredService().CreateLspMiscellaneousFilesWorkspace(lspServices, hostServices)); + AddLazyService(lspServices => lspServices.GetRequiredService().CreateLspMiscellaneousFilesWorkspaceProvider(lspServices, hostServices)); return baseServiceMap.ToFrozenDictionary( keySelector: kvp => kvp.Key, diff --git a/src/roslyn/src/LanguageServer/Protocol/Workspaces/ILspMiscellaneousFilesWorkspaceProvider.cs b/src/roslyn/src/LanguageServer/Protocol/Workspaces/ILspMiscellaneousFilesWorkspaceProvider.cs new file mode 100644 index 00000000000..17c4f6e82f4 --- /dev/null +++ b/src/roslyn/src/LanguageServer/Protocol/Workspaces/ILspMiscellaneousFilesWorkspaceProvider.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CommonLanguageServerProtocol.Framework; + +namespace Microsoft.CodeAnalysis.LanguageServer; + +internal interface ILspMiscellaneousFilesWorkspaceProvider : ILspService +{ + /// + /// Returns the actual workspace that the documents are added to or removed from. + /// + Workspace Workspace { get; } + TextDocument? AddMiscellaneousDocument(Uri uri, SourceText documentText, string languageId, ILspLogger logger); + void TryRemoveMiscellaneousDocument(Uri uri, bool removeFromMetadataWorkspace); +} diff --git a/src/roslyn/src/LanguageServer/Protocol/Workspaces/ILspMiscellaneousFilesWorkspaceProviderFactory.cs b/src/roslyn/src/LanguageServer/Protocol/Workspaces/ILspMiscellaneousFilesWorkspaceProviderFactory.cs new file mode 100644 index 00000000000..8386c4ae080 --- /dev/null +++ b/src/roslyn/src/LanguageServer/Protocol/Workspaces/ILspMiscellaneousFilesWorkspaceProviderFactory.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.Host; +using Microsoft.CommonLanguageServerProtocol.Framework; + +namespace Microsoft.CodeAnalysis.LanguageServer; + +internal interface ILspMiscellaneousFilesWorkspaceProviderFactory : ILspService +{ + ILspMiscellaneousFilesWorkspaceProvider CreateLspMiscellaneousFilesWorkspaceProvider(ILspServices lspServices, HostServices hostServices); +} diff --git a/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspace.cs b/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspace.cs deleted file mode 100644 index 6baf6e5f6c9..00000000000 --- a/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspace.cs +++ /dev/null @@ -1,129 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Features.Workspaces; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.MetadataAsSource; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Text; -using Microsoft.CommonLanguageServerProtocol.Framework; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.LanguageServer; - -/// -/// Defines a default workspace for opened LSP files that are not found in any -/// workspace registered by the . -/// If a document added here is subsequently found in a registered workspace, -/// the document is removed from this workspace. -/// -/// Future work for this workspace includes supporting basic metadata references (mscorlib, System dlls, etc), -/// but that is dependent on having a x-plat mechanism for retrieving those references from the framework / sdk. -/// -internal sealed class LspMiscellaneousFilesWorkspace(ILspServices lspServices, IMetadataAsSourceFileService metadataAsSourceFileService, HostServices hostServices) - : Workspace(hostServices, WorkspaceKind.MiscellaneousFiles), ILspService, ILspWorkspace -{ - public bool SupportsMutation => true; - - /// - /// Takes in a file URI and text and creates a misc project and document for the file. - /// - /// Calls to this method and are made - /// from LSP text sync request handling which do not run concurrently. - /// - public TextDocument? AddMiscellaneousDocument(Uri uri, SourceText documentText, string languageId, ILspLogger logger) - { - var documentFilePath = ProtocolConversions.GetDocumentFilePathFromUri(uri); - - var container = new StaticSourceTextContainer(documentText); - if (metadataAsSourceFileService.TryAddDocumentToWorkspace(documentFilePath, container, out var documentId)) - { - var metadataWorkspace = metadataAsSourceFileService.TryGetWorkspace(); - Contract.ThrowIfNull(metadataWorkspace); - var document = metadataWorkspace.CurrentSolution.GetRequiredDocument(documentId); - return document; - } - - var languageInfoProvider = lspServices.GetRequiredService(); - if (!languageInfoProvider.TryGetLanguageInformation(uri, languageId, out var languageInformation)) - { - // Only log here since throwing here could take down the LSP server. - logger.LogError($"Could not find language information for {uri} with absolute path {documentFilePath}"); - return null; - } - - var sourceTextLoader = new SourceTextLoader(documentText, documentFilePath); - - var projectInfo = MiscellaneousFileUtilities.CreateMiscellaneousProjectInfoForDocument( - this, documentFilePath, sourceTextLoader, languageInformation, documentText.ChecksumAlgorithm, Services.SolutionServices, []); - OnProjectAdded(projectInfo); - - if (languageInformation.LanguageName == "Razor") - { - var docId = projectInfo.AdditionalDocuments.Single().Id; - return CurrentSolution.GetRequiredAdditionalDocument(docId); - } - - var id = projectInfo.Documents.Single().Id; - return CurrentSolution.GetRequiredDocument(id); - } - - /// - /// Removes a document with the matching file path from this workspace. - /// - /// Calls to this method and are made - /// from LSP text sync request handling which do not run concurrently. - /// - public void TryRemoveMiscellaneousDocument(Uri uri, bool removeFromMetadataWorkspace) - { - var documentFilePath = ProtocolConversions.GetDocumentFilePathFromUri(uri); - if (removeFromMetadataWorkspace && metadataAsSourceFileService.TryRemoveDocumentFromWorkspace(documentFilePath)) - { - return; - } - - // We'll only ever have a single document matching this URI in the misc solution. - var matchingDocument = CurrentSolution.GetDocumentIds(uri).SingleOrDefault(); - if (matchingDocument != null) - { - if (CurrentSolution.ContainsDocument(matchingDocument)) - { - OnDocumentRemoved(matchingDocument); - } - else if (CurrentSolution.ContainsAdditionalDocument(matchingDocument)) - { - OnAdditionalDocumentRemoved(matchingDocument); - } - - // Also remove the project - we always create a new project for each misc file we add - // so it should never have other documents in it. - var project = CurrentSolution.GetRequiredProject(matchingDocument.ProjectId); - OnProjectRemoved(project.Id); - } - } - - public ValueTask UpdateTextIfPresentAsync(DocumentId documentId, SourceText sourceText, CancellationToken cancellationToken) - { - this.OnDocumentTextChanged(documentId, sourceText, PreservationMode.PreserveIdentity, requireDocumentPresent: false); - return ValueTaskFactory.CompletedTask; - } - - private sealed class StaticSourceTextContainer(SourceText text) : SourceTextContainer - { - public override SourceText CurrentText => text; - - /// - /// Text changes are handled by LSP forking the document, we don't need to actually update anything here. - /// - public override event EventHandler TextChanged - { - add { } - remove { } - } - } -} diff --git a/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspaceProvider.cs b/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspaceProvider.cs index 61dd7b2ae8d..a0513e44b11 100644 --- a/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspaceProvider.cs +++ b/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspaceProvider.cs @@ -3,27 +3,130 @@ // See the LICENSE file in the project root for more information. using System; -using System.Composition; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Features.Workspaces; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CodeAnalysis.MetadataAsSource; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; using Microsoft.CommonLanguageServerProtocol.Framework; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer; /// -/// Service to create instances. -/// This is not exported as a as it requires -/// special base language server dependencies such as the +/// Defines a default workspace for opened LSP files that are not found in any +/// workspace registered by the . +/// If a document added here is subsequently found in a registered workspace, +/// the document is removed from this workspace. +/// +/// Future work for this workspace includes supporting basic metadata references (mscorlib, System dlls, etc), +/// but that is dependent on having a x-plat mechanism for retrieving those references from the framework / sdk. /// -[ExportCSharpVisualBasicStatelessLspService(typeof(LspMiscellaneousFilesWorkspaceProvider)), Shared] -[method: ImportingConstructor] -[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] -internal sealed class LspMiscellaneousFilesWorkspaceProvider(IMetadataAsSourceFileService metadataAsSourceFileService) : ILspService +internal sealed class LspMiscellaneousFilesWorkspaceProvider(ILspServices lspServices, IMetadataAsSourceFileService metadataAsSourceFileService, HostServices hostServices) + : Workspace(hostServices, WorkspaceKind.MiscellaneousFiles), ILspMiscellaneousFilesWorkspaceProvider, ILspWorkspace { - public LspMiscellaneousFilesWorkspace CreateLspMiscellaneousFilesWorkspace(ILspServices lspServices, HostServices hostServices) + public bool SupportsMutation => true; + + // For this implementation, it's easiest to just have it inherit from Workspace, so we'll just return this. + public Workspace Workspace => this; + + /// + /// Takes in a file URI and text and creates a misc project and document for the file. + /// + /// Calls to this method and are made + /// from LSP text sync request handling which do not run concurrently. + /// + public TextDocument? AddMiscellaneousDocument(Uri uri, SourceText documentText, string languageId, ILspLogger logger) + { + var documentFilePath = ProtocolConversions.GetDocumentFilePathFromUri(uri); + + var container = new StaticSourceTextContainer(documentText); + if (metadataAsSourceFileService.TryAddDocumentToWorkspace(documentFilePath, container, out var documentId)) + { + var metadataWorkspace = metadataAsSourceFileService.TryGetWorkspace(); + Contract.ThrowIfNull(metadataWorkspace); + var document = metadataWorkspace.CurrentSolution.GetRequiredDocument(documentId); + return document; + } + + var languageInfoProvider = lspServices.GetRequiredService(); + if (!languageInfoProvider.TryGetLanguageInformation(uri, languageId, out var languageInformation)) + { + // Only log here since throwing here could take down the LSP server. + logger.LogError($"Could not find language information for {uri} with absolute path {documentFilePath}"); + return null; + } + + var sourceTextLoader = new SourceTextLoader(documentText, documentFilePath); + + var projectInfo = MiscellaneousFileUtilities.CreateMiscellaneousProjectInfoForDocument( + this, documentFilePath, sourceTextLoader, languageInformation, documentText.ChecksumAlgorithm, Services.SolutionServices, []); + OnProjectAdded(projectInfo); + + if (languageInformation.LanguageName == "Razor") + { + var docId = projectInfo.AdditionalDocuments.Single().Id; + return CurrentSolution.GetRequiredAdditionalDocument(docId); + } + + var id = projectInfo.Documents.Single().Id; + return CurrentSolution.GetRequiredDocument(id); + } + + /// + /// Removes a document with the matching file path from this workspace. + /// + /// Calls to this method and are made + /// from LSP text sync request handling which do not run concurrently. + /// + public void TryRemoveMiscellaneousDocument(Uri uri, bool removeFromMetadataWorkspace) + { + var documentFilePath = ProtocolConversions.GetDocumentFilePathFromUri(uri); + if (removeFromMetadataWorkspace && metadataAsSourceFileService.TryRemoveDocumentFromWorkspace(documentFilePath)) + { + return; + } + + // We'll only ever have a single document matching this URI in the misc solution. + var matchingDocument = CurrentSolution.GetDocumentIds(uri).SingleOrDefault(); + if (matchingDocument != null) + { + if (CurrentSolution.ContainsDocument(matchingDocument)) + { + OnDocumentRemoved(matchingDocument); + } + else if (CurrentSolution.ContainsAdditionalDocument(matchingDocument)) + { + OnAdditionalDocumentRemoved(matchingDocument); + } + + // Also remove the project - we always create a new project for each misc file we add + // so it should never have other documents in it. + var project = CurrentSolution.GetRequiredProject(matchingDocument.ProjectId); + OnProjectRemoved(project.Id); + } + } + + public ValueTask UpdateTextIfPresentAsync(DocumentId documentId, SourceText sourceText, CancellationToken cancellationToken) { - return new LspMiscellaneousFilesWorkspace(lspServices, metadataAsSourceFileService, hostServices); + this.OnDocumentTextChanged(documentId, sourceText, PreservationMode.PreserveIdentity, requireDocumentPresent: false); + return ValueTaskFactory.CompletedTask; + } + + private sealed class StaticSourceTextContainer(SourceText text) : SourceTextContainer + { + public override SourceText CurrentText => text; + + /// + /// Text changes are handled by LSP forking the document, we don't need to actually update anything here. + /// + public override event EventHandler TextChanged + { + add { } + remove { } + } } } diff --git a/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspaceProviderFactory.cs b/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspaceProviderFactory.cs new file mode 100644 index 00000000000..568903cd80a --- /dev/null +++ b/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspaceProviderFactory.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Composition; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Microsoft.CodeAnalysis.MetadataAsSource; +using Microsoft.CommonLanguageServerProtocol.Framework; + +namespace Microsoft.CodeAnalysis.LanguageServer; + +/// +/// Service to create instances. +/// This is not exported as a as it requires +/// special base language server dependencies such as the +/// +[ExportCSharpVisualBasicStatelessLspService(typeof(ILspMiscellaneousFilesWorkspaceProviderFactory)), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class LspMiscellaneousFilesWorkspaceProviderFactory(IMetadataAsSourceFileService metadataAsSourceFileService) : ILspMiscellaneousFilesWorkspaceProviderFactory +{ + public ILspMiscellaneousFilesWorkspaceProvider CreateLspMiscellaneousFilesWorkspaceProvider(ILspServices lspServices, HostServices hostServices) + { + return new LspMiscellaneousFilesWorkspaceProvider(lspServices, metadataAsSourceFileService, hostServices); + } +} diff --git a/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs b/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs index 05ff78b1f06..cf1ee04f2ac 100644 --- a/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs +++ b/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs @@ -115,19 +115,19 @@ public int GetHashCode(Uri obj) private ImmutableDictionary _trackedDocuments = ImmutableDictionary.Empty.WithComparers(LspUriComparer.Instance); private readonly ILspLogger _logger; - private readonly LspMiscellaneousFilesWorkspace? _lspMiscellaneousFilesWorkspace; + private readonly ILspMiscellaneousFilesWorkspaceProvider? _lspMiscellaneousFilesWorkspaceProvider; private readonly LspWorkspaceRegistrationService _lspWorkspaceRegistrationService; private readonly ILanguageInfoProvider _languageInfoProvider; private readonly RequestTelemetryLogger _requestTelemetryLogger; public LspWorkspaceManager( ILspLogger logger, - LspMiscellaneousFilesWorkspace? lspMiscellaneousFilesWorkspace, + ILspMiscellaneousFilesWorkspaceProvider? lspMiscellaneousFilesWorkspace, LspWorkspaceRegistrationService lspWorkspaceRegistrationService, ILanguageInfoProvider languageInfoProvider, RequestTelemetryLogger requestTelemetryLogger) { - _lspMiscellaneousFilesWorkspace = lspMiscellaneousFilesWorkspace; + _lspMiscellaneousFilesWorkspaceProvider = lspMiscellaneousFilesWorkspace; _logger = logger; _requestTelemetryLogger = requestTelemetryLogger; @@ -197,7 +197,7 @@ public async ValueTask StopTrackingAsync(Uri uri, CancellationToken cancellation _cachedLspSolutions.Clear(); // Also remove it from our loose files or metadata workspace if it is still there. - _lspMiscellaneousFilesWorkspace?.TryRemoveMiscellaneousDocument(uri, removeFromMetadataWorkspace: true); + _lspMiscellaneousFilesWorkspaceProvider?.TryRemoveMiscellaneousDocument(uri, removeFromMetadataWorkspace: true); LspTextChanged?.Invoke(this, EventArgs.Empty); @@ -295,10 +295,10 @@ public void UpdateTrackedDocument(Uri uri, SourceText newSourceText) // As we found the document in a non-misc workspace, also attempt to remove it from the misc workspace // if it happens to be in there as well. - if (workspace != _lspMiscellaneousFilesWorkspace) + if (workspace != _lspMiscellaneousFilesWorkspaceProvider?.Workspace) { // Do not attempt to remove the file from the metadata workspace (the document is still open). - _lspMiscellaneousFilesWorkspace?.TryRemoveMiscellaneousDocument(uri, removeFromMetadataWorkspace: false); + _lspMiscellaneousFilesWorkspaceProvider?.TryRemoveMiscellaneousDocument(uri, removeFromMetadataWorkspace: false); } return (workspace, document.Project.Solution, document); @@ -311,10 +311,10 @@ public void UpdateTrackedDocument(Uri uri, SourceText newSourceText) _logger.LogInformation($"Could not find '{textDocumentIdentifier.Uri}'. Searched {searchedWorkspaceKinds}"); _requestTelemetryLogger.UpdateFindDocumentTelemetryData(success: false, workspaceKind: null); - // Add the document to our loose files workspace (if we have one) if it iss open. + // Add the document to our loose files workspace (if we have one) if it is open. if (_trackedDocuments.TryGetValue(uri, out var trackedDocument)) { - var miscDocument = _lspMiscellaneousFilesWorkspace?.AddMiscellaneousDocument(uri, trackedDocument.Text, trackedDocument.LanguageId, _logger); + var miscDocument = _lspMiscellaneousFilesWorkspaceProvider?.AddMiscellaneousDocument(uri, trackedDocument.Text, trackedDocument.LanguageId, _logger); if (miscDocument is not null) return (miscDocument.Project.Solution.Workspace, miscDocument.Project.Solution, miscDocument); } @@ -582,8 +582,10 @@ internal readonly struct TestAccessor public TestAccessor(LspWorkspaceManager manager) => _manager = manager; - public LspMiscellaneousFilesWorkspace? GetLspMiscellaneousFilesWorkspace() - => _manager._lspMiscellaneousFilesWorkspace; + public Workspace? GetLspMiscellaneousFilesWorkspace() + { + return _manager._lspMiscellaneousFilesWorkspaceProvider?.Workspace; + } public bool IsWorkspaceRegistered(Workspace workspace) { diff --git a/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManagerFactory.cs b/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManagerFactory.cs index fd6c30ad6c9..d805ca8504a 100644 --- a/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManagerFactory.cs +++ b/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManagerFactory.cs @@ -25,7 +25,7 @@ public LspWorkspaceManagerFactory(LspWorkspaceRegistrationService lspWorkspaceRe public ILspService CreateILspService(LspServices lspServices, WellKnownLspServerKinds serverKind) { var logger = lspServices.GetRequiredService(); - var miscFilesWorkspace = lspServices.GetService(); + var miscFilesWorkspace = lspServices.GetService(); var languageInfoProvider = lspServices.GetRequiredService(); var telemetryLogger = lspServices.GetRequiredService(); return new LspWorkspaceManager(logger, miscFilesWorkspace, _workspaceRegistrationService, languageInfoProvider, telemetryLogger); diff --git a/src/roslyn/src/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs b/src/roslyn/src/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs index 636e373f14d..d272e37c274 100644 --- a/src/roslyn/src/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs +++ b/src/roslyn/src/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.Build.Evaluation; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Test.Utilities; using Roslyn.Text.Adornments; @@ -526,6 +527,64 @@ public async Task DoAsync() expectedLocation).ConfigureAwait(false); Assert.Equal(expectedMarkdown, results.Contents.Fourth.Value); } + [Theory, CombinatorialData] + public async Task TestGetHoverAsync_UsesNonBreakingSpaceForSupportedPlatforms(bool mutatingLspWorkspace) + { + var source = """ + using System; + class WithConstant + { + #if NET472 + public const string Target = "Target in net472"; + #endif + } + class Program + { + static void Main(string[] args) + { + Console.WriteLine(WithConstant.{|caret:Target|}); + } + } + """; + + var workspaceXml = + $""" + + + + + + + + + """; + + var expectedMarkdown = $""" + ```csharp + ({FeaturesResources.constant}) string WithConstant.Target = "Target in net472" + ``` + + +     {string.Format(FeaturesResources._0_1, "Net472", FeaturesResources.Available).Replace("-", "\\-")} +     {string.Format(FeaturesResources._0_1, "NetCoreApp3", FeaturesResources.Not_Available).Replace("-", "\\-")} + + {FeaturesResources.You_can_use_the_navigation_bar_to_switch_contexts.Replace(".", "\\.")} + + """; + + var clientCapabilities = new LSP.ClientCapabilities + { + TextDocument = new LSP.TextDocumentClientCapabilities { Hover = new LSP.HoverSetting { ContentFormat = [LSP.MarkupKind.Markdown] } } + }; + await using var testLspServer = await CreateXmlTestLspServerAsync(workspaceXml, mutatingLspWorkspace, initializationOptions: new InitializationOptions { ClientCapabilities = clientCapabilities }); + var location = testLspServer.GetLocations("caret").Single(); + + var project = testLspServer.GetCurrentSolution().Projects.Single(p => p.AssemblyName == "Net472"); + var result = await RunGetHoverAsync(testLspServer, location, project.Id); + + AssertEx.NotNull(result); + Assert.Equal(expectedMarkdown, result.Contents.Fourth.Value); + } private static async Task RunGetHoverAsync( TestLspServer testLspServer, diff --git a/src/roslyn/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs b/src/roslyn/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs index 5c06a1171e1..4ba9d8f8dfa 100644 --- a/src/roslyn/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs +++ b/src/roslyn/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs @@ -56,7 +56,7 @@ void M() // Create a server that supports LSP misc files and verify no misc files present. await using var testLspServer = await CreateTestLspServerAsync(string.Empty, mutatingLspWorkspace, new InitializationOptions { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }); - var miscWorkspace = testLspServer.GetRequiredLspService(); + var miscWorkspace = testLspServer.GetManager().GetTestAccessor().GetLspMiscellaneousFilesWorkspace(); testLspServer.TestWorkspace.GetService().Register(miscWorkspace); Assert.Null(GetMiscellaneousDocument(testLspServer)); diff --git a/src/roslyn/src/LanguageServer/ProtocolUnitTests/UriTests.cs b/src/roslyn/src/LanguageServer/ProtocolUnitTests/UriTests.cs index e8195746a11..0d207c389f4 100644 --- a/src/roslyn/src/LanguageServer/ProtocolUnitTests/UriTests.cs +++ b/src/roslyn/src/LanguageServer/ProtocolUnitTests/UriTests.cs @@ -49,7 +49,7 @@ void M() // Verify file is added to the misc file workspace. var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = looseFileUri }, CancellationToken.None); - Assert.True(workspace is LspMiscellaneousFilesWorkspace); + Assert.Equal(testLspServer.GetManager().GetTestAccessor().GetLspMiscellaneousFilesWorkspace(), workspace); AssertEx.NotNull(document); Assert.Equal(looseFileUri, document.GetURI()); Assert.Equal(filePath, document.FilePath); @@ -75,7 +75,7 @@ void M() // Verify file is added to the misc file workspace. var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = looseFileUri }, CancellationToken.None); - Assert.True(workspace is LspMiscellaneousFilesWorkspace); + Assert.Equal(testLspServer.GetManager().GetTestAccessor().GetLspMiscellaneousFilesWorkspace(), workspace); AssertEx.NotNull(document); Assert.Equal(looseFileUri, document.GetURI()); Assert.Equal(looseFileUri.OriginalString, document.FilePath); @@ -107,7 +107,7 @@ public class A // Verify file is not added to the misc file workspace. { var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = expectedDocumentUri }, CancellationToken.None); - Assert.False(workspace is LspMiscellaneousFilesWorkspace); + Assert.NotEqual(testLspServer.GetManager().GetTestAccessor().GetLspMiscellaneousFilesWorkspace(), workspace); AssertEx.NotNull(document); Assert.Equal(expectedDocumentUri, document.GetURI()); Assert.Equal(documentFilePath, document.FilePath); @@ -118,7 +118,7 @@ public class A var lowercaseUri = ProtocolConversions.CreateAbsoluteUri(documentFilePath.ToLowerInvariant()); Assert.NotEqual(expectedDocumentUri.AbsolutePath, lowercaseUri.AbsolutePath); var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = lowercaseUri }, CancellationToken.None); - Assert.False(workspace is LspMiscellaneousFilesWorkspace); + Assert.NotEqual(testLspServer.GetManager().GetTestAccessor().GetLspMiscellaneousFilesWorkspace(), workspace); AssertEx.NotNull(document); Assert.Equal(expectedDocumentUri, document.GetURI()); Assert.Equal(documentFilePath, document.FilePath); @@ -307,7 +307,7 @@ public async Task TestDoesNotCrashIfUnableToDetermineLanguageInfo(bool mutatingL // Verify file is added to the misc file workspace. var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = looseFileUri }, CancellationToken.None); - Assert.True(workspace is LspMiscellaneousFilesWorkspace); + Assert.Equal(testLspServer.GetManager().GetTestAccessor().GetLspMiscellaneousFilesWorkspace(), workspace); AssertEx.NotNull(document); Assert.Equal(looseFileUri, document.GetURI()); Assert.Equal(looseFileUri.OriginalString, document.FilePath); diff --git a/src/roslyn/src/NuGet/VS.ExternalAPIs.Roslyn.Package/VS.ExternalAPIs.Roslyn.Package.csproj b/src/roslyn/src/NuGet/VS.ExternalAPIs.Roslyn.Package/VS.ExternalAPIs.Roslyn.Package.csproj index 0519d334523..c0fa45a07f5 100644 --- a/src/roslyn/src/NuGet/VS.ExternalAPIs.Roslyn.Package/VS.ExternalAPIs.Roslyn.Package.csproj +++ b/src/roslyn/src/NuGet/VS.ExternalAPIs.Roslyn.Package/VS.ExternalAPIs.Roslyn.Package.csproj @@ -72,22 +72,22 @@ - <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.CSharp.EditorFeatures\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.CSharp.EditorFeatures.dll" TargetDir="" /> + <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.CSharp.EditorFeatures\$(Configuration)\net472\Microsoft.CodeAnalysis.CSharp.EditorFeatures.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.CSharp.Features\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.CSharp.Features.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.CSharp.Scripting\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.CSharp.Scripting.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.CSharp.Workspaces\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.CSharp.Workspaces.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.CSharp\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.CSharp.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.EditorFeatures.Text\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.EditorFeatures.Text.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.EditorFeatures.Wpf\$(Configuration)\net472\Microsoft.CodeAnalysis.EditorFeatures.Wpf.dll" TargetDir="" /> - <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.EditorFeatures\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.EditorFeatures.dll" TargetDir="" /> + <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.EditorFeatures\$(Configuration)\net472\Microsoft.CodeAnalysis.EditorFeatures.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.ExternalAccess.Apex\$(Configuration)\net472\Microsoft.CodeAnalysis.ExternalAccess.Apex.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.ExternalAccess.AspNetCore\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.ExternalAccess.AspNetCore.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.ExternalAccess.Copilot\$(Configuration)\net472\Microsoft.CodeAnalysis.ExternalAccess.Copilot.dll" TargetDir="" /> - <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.ExternalAccess.Debugger\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.ExternalAccess.Debugger.dll" TargetDir="" /> + <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.ExternalAccess.Debugger\$(Configuration)\net472\Microsoft.CodeAnalysis.ExternalAccess.Debugger.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.ExternalAccess.EditorConfigGenerator\$(Configuration)\net472\Microsoft.CodeAnalysis.ExternalAccess.EditorConfigGenerator.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.ExternalAccess.Extensions\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.ExternalAccess.Extensions.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.ExternalAccess.FSharp\$(Configuration)\net472\Microsoft.CodeAnalysis.ExternalAccess.FSharp.dll" TargetDir="" /> - <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.ExternalAccess.Razor.EditorFeatures\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.ExternalAccess.Razor.EditorFeatures.dll" TargetDir="" /> + <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.ExternalAccess.Razor.EditorFeatures\$(Configuration)\net472\Microsoft.CodeAnalysis.ExternalAccess.Razor.EditorFeatures.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.ExternalAccess.Razor.Features\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.ExternalAccess.Razor.Features.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.Features\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.Features.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.InteractiveHost\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.InteractiveHost.dll" TargetDir="" /> @@ -95,7 +95,7 @@ <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.Remote.ServiceHub\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.Remote.ServiceHub.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.Remote.Workspaces\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.Remote.Workspaces.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.Scripting\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.Scripting.dll" TargetDir="" /> - <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.VisualBasic.EditorFeatures\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.VisualBasic.EditorFeatures.dll" TargetDir="" /> + <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.VisualBasic.EditorFeatures\$(Configuration)\net472\Microsoft.CodeAnalysis.VisualBasic.EditorFeatures.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.VisualBasic.Features\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.VisualBasic.Features.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.VisualBasic.Workspaces\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll" TargetDir="" /> <_File Include="$(ArtifactsBinDir)Microsoft.CodeAnalysis.VisualBasic\$(Configuration)\netstandard2.0\Microsoft.CodeAnalysis.VisualBasic.dll" TargetDir="" /> diff --git a/src/roslyn/src/Tools/ExternalAccess/Razor/EditorFeatures/Microsoft.CodeAnalysis.ExternalAccess.Razor.EditorFeatures.csproj b/src/roslyn/src/Tools/ExternalAccess/Razor/EditorFeatures/Microsoft.CodeAnalysis.ExternalAccess.Razor.EditorFeatures.csproj index 95c43479506..558672dedaf 100644 --- a/src/roslyn/src/Tools/ExternalAccess/Razor/EditorFeatures/Microsoft.CodeAnalysis.ExternalAccess.Razor.EditorFeatures.csproj +++ b/src/roslyn/src/Tools/ExternalAccess/Razor/EditorFeatures/Microsoft.CodeAnalysis.ExternalAccess.Razor.EditorFeatures.csproj @@ -1,9 +1,10 @@  - + Microsoft.CodeAnalysis.ExternalAccess.Razor - $(NetVS);netstandard2.0 + net472 + true true @@ -60,4 +61,4 @@ - + \ No newline at end of file diff --git a/src/roslyn/src/VisualStudio/Core/Def/LanguageClient/VisualStudioLspWorkspaceRegistrationService.cs b/src/roslyn/src/VisualStudio/Core/Def/LanguageClient/VisualStudioLspWorkspaceRegistrationService.cs index 964672257f1..24f01d5520d 100644 --- a/src/roslyn/src/VisualStudio/Core/Def/LanguageClient/VisualStudioLspWorkspaceRegistrationService.cs +++ b/src/roslyn/src/VisualStudio/Core/Def/LanguageClient/VisualStudioLspWorkspaceRegistrationService.cs @@ -16,17 +16,4 @@ internal sealed class VisualStudioLspWorkspaceRegistrationService : LspWorkspace public VisualStudioLspWorkspaceRegistrationService() { } - - public override void Register(Workspace? workspace) - { - // The lsp misc files workspace has the MiscellaneousFiles workspace kind, - // but we don't actually want to mark it as a registered workspace in VS since we - // prefer the actual MiscellaneousFilesWorkspace. - if (workspace is LspMiscellaneousFilesWorkspace) - { - return; - } - - base.Register(workspace); - } } diff --git a/src/roslyn/src/VisualStudio/Xaml/Impl/Features/Peek/IXamlPeekableItemFactory.cs b/src/roslyn/src/VisualStudio/Xaml/Impl/Features/Peek/IXamlPeekableItemFactory.cs new file mode 100644 index 00000000000..3134d0201d5 --- /dev/null +++ b/src/roslyn/src/VisualStudio/Xaml/Impl/Features/Peek/IXamlPeekableItemFactory.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable disable + +using System; +using System.Collections.Generic; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.Implementation.Peek; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.MetadataAsSource; +using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.Language.Intellisense; + +namespace Microsoft.VisualStudio.LanguageServices.Xaml.Features.Peek; + +internal interface IXamlPeekableItemFactory +{ + Task> GetPeekableItemsAsync(ISymbol symbol, Project project, IPeekResultFactory peekResultFactory, CancellationToken cancellationToken); +} + +[Export(typeof(IXamlPeekableItemFactory)), Shared] +[method: ImportingConstructor] +[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] +internal sealed class XamlPeekableItemFactory( + IMetadataAsSourceFileService metadataAsSourceFileService, + IGlobalOptionService globalOptions, + IThreadingContext threadingContext) : PeekableItemFactory(metadataAsSourceFileService, globalOptions, threadingContext); diff --git a/src/roslyn/src/Workspaces/Core/Portable/Workspace/Solution/Solution.cs b/src/roslyn/src/Workspaces/Core/Portable/Workspace/Solution/Solution.cs index a192c88d573..f2087991393 100644 --- a/src/roslyn/src/Workspaces/Core/Portable/Workspace/Solution/Solution.cs +++ b/src/roslyn/src/Workspaces/Core/Portable/Workspace/Solution/Solution.cs @@ -1643,7 +1643,7 @@ internal Document WithFrozenSourceGeneratedDocument( } internal Solution WithFrozenSourceGeneratedDocuments(ImmutableArray<(SourceGeneratedDocumentIdentity documentIdentity, DateTime generationDateTime, SourceText text)> documents) - => WithCompilationState(CompilationState.WithFrozenSourceGeneratedDocuments(documents.SelectAsArray(d => (d.documentIdentity, d.generationDateTime, d.text, (SyntaxNode?)null)))); + => WithCompilationState(CompilationState.WithFrozenSourceGeneratedDocuments(documents.SelectAsArray(d => (d.documentIdentity, d.generationDateTime, (SourceText?)d.text, (SyntaxNode?)null)))); /// internal Solution UpdateSpecificSourceGeneratorExecutionVersions(SourceGeneratorExecutionVersionMap sourceGeneratorExecutionVersionMap) diff --git a/src/roslyn/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs b/src/roslyn/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs index cb1a742907d..49918b82a5f 100644 --- a/src/roslyn/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs +++ b/src/roslyn/src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs @@ -796,13 +796,13 @@ internal SolutionCompilationState WithDocumentTexts(ImmutableArray<(DocumentId d SourceTextIsUnchanged(oldDocumentState, text) ? oldDocumentState : oldDocumentState.UpdateText(text, mode)); (ImmutableArray<(DocumentId, SourceText)>, - ImmutableArray<(SourceGeneratedDocumentIdentity, DateTime, SourceText, SyntaxNode?)>) GetOrdinaryAndSourceGeneratedDocuments() + ImmutableArray<(SourceGeneratedDocumentIdentity, DateTime, SourceText?, SyntaxNode?)>) GetOrdinaryAndSourceGeneratedDocuments() { if (!texts.Any(static t => t.documentId.IsSourceGenerated)) return (texts, []); using var _1 = ArrayBuilder<(DocumentId, SourceText)>.GetInstance(capacity: texts.Length, out var ordinaryDocuments); - using var _2 = ArrayBuilder<(SourceGeneratedDocumentIdentity, DateTime, SourceText, SyntaxNode?)>.GetInstance(out var sourceGeneratedDocuments); + using var _2 = ArrayBuilder<(SourceGeneratedDocumentIdentity, DateTime, SourceText?, SyntaxNode?)>.GetInstance(out var sourceGeneratedDocuments); foreach (var doc in texts) { if (!doc.documentId.IsSourceGenerated) @@ -828,7 +828,7 @@ private static bool SourceTextIsUnchanged(DocumentState oldDocument, SourceText /// private SolutionCompilationState UpdateDocumentsInMultipleProjects( ImmutableArray<(DocumentId documentId, TDocumentData documentData)> documentsToUpdate, - ImmutableArray<(SourceGeneratedDocumentIdentity documentIdentity, DateTime generationDateTime, SourceText sourceText, SyntaxNode? syntaxNode)> sourceGeneratedDocuments, + ImmutableArray<(SourceGeneratedDocumentIdentity documentIdentity, DateTime generationDateTime, SourceText? sourceText, SyntaxNode? syntaxNode)> sourceGeneratedDocuments, TArg arg, Func updateDocument) where TDocumentState : TextDocumentState @@ -1001,13 +1001,13 @@ public SolutionCompilationState WithDocumentSyntaxRoots(ImmutableArray<(Document : oldDocumentState.UpdateTree(root, mode)); (ImmutableArray<(DocumentId, SyntaxNode)>, - ImmutableArray<(SourceGeneratedDocumentIdentity, DateTime, SourceText, SyntaxNode?)>) GetOrdinaryAndSourceGeneratedDocuments() + ImmutableArray<(SourceGeneratedDocumentIdentity, DateTime, SourceText?, SyntaxNode?)>) GetOrdinaryAndSourceGeneratedDocuments() { if (!syntaxRoots.Any(static t => t.documentId.IsSourceGenerated)) return (syntaxRoots, []); using var _1 = ArrayBuilder<(DocumentId, SyntaxNode)>.GetInstance(capacity: syntaxRoots.Length, out var ordinaryDocuments); - using var _2 = ArrayBuilder<(SourceGeneratedDocumentIdentity, DateTime, SourceText, SyntaxNode?)>.GetInstance(out var sourceGeneratedDocuments); + using var _2 = ArrayBuilder<(SourceGeneratedDocumentIdentity, DateTime, SourceText?, SyntaxNode?)>.GetInstance(out var sourceGeneratedDocuments); foreach (var doc in syntaxRoots) { if (!doc.documentId.IsSourceGenerated) @@ -1016,9 +1016,7 @@ public SolutionCompilationState WithDocumentSyntaxRoots(ImmutableArray<(Document } else if (TryGetSourceGeneratedDocumentStateForAlreadyGeneratedId(doc.documentId) is { Identity: var identity }) { - // Source generated documents always do a full parse, and source generator authors are only allowed to provide - // strings, so we follow suit here and just take the text from the root. - sourceGeneratedDocuments.Add((identity, DateTime.UtcNow, doc.root.GetText(), doc.root)); + sourceGeneratedDocuments.Add((identity, DateTime.UtcNow, null, doc.root)); } } @@ -1385,7 +1383,7 @@ public SolutionCompilationState WithoutFrozenSourceGeneratedDocuments() /// generated file open, we need to make sure everything lines up. /// public SolutionCompilationState WithFrozenSourceGeneratedDocuments( - ImmutableArray<(SourceGeneratedDocumentIdentity documentIdentity, DateTime generationDateTime, SourceText sourceText, SyntaxNode? syntaxNode)> documents) + ImmutableArray<(SourceGeneratedDocumentIdentity documentIdentity, DateTime generationDateTime, SourceText? sourceText, SyntaxNode? syntaxNode)> documents) { if (documents.IsEmpty) return this; @@ -1394,16 +1392,23 @@ public SolutionCompilationState WithFrozenSourceGeneratedDocuments( using var _ = PooledDictionary.GetInstance(out var documentStates); foreach (var (documentIdentity, generationDateTime, sourceText, syntaxNode) in documents) { + Contract.ThrowIfTrue(sourceText is null && syntaxNode is null); + Contract.ThrowIfTrue(sourceText is not null && syntaxNode is not null); + var existingGeneratedState = TryGetSourceGeneratedDocumentStateForAlreadyGeneratedId(documentIdentity.DocumentId); if (existingGeneratedState != null) { var newGeneratedState = existingGeneratedState - .WithText(sourceText) .WithParseOptions(existingGeneratedState.ParseOptions) .WithGenerationDateTime(generationDateTime); - if (syntaxNode != null) + if (sourceText != null) + { + newGeneratedState = newGeneratedState.WithText(sourceText); + } + else { + Contract.ThrowIfNull(syntaxNode); newGeneratedState = newGeneratedState.WithSyntaxRoot(syntaxNode); } @@ -1420,17 +1425,13 @@ public SolutionCompilationState WithFrozenSourceGeneratedDocuments( var newGeneratedState = SourceGeneratedDocumentState.Create( documentIdentity, sourceText, + syntaxNode, projectState.ParseOptions!, projectState.LanguageServices, // Just compute the checksum from the source text passed in. originalSourceTextChecksum: null, generationDateTime); - if (syntaxNode != null) - { - newGeneratedState = newGeneratedState.WithSyntaxRoot(syntaxNode); - } - documentStates.Add(newGeneratedState.Id, newGeneratedState); } } diff --git a/src/roslyn/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs b/src/roslyn/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs index 53d2ae70681..674b15cac7c 100644 --- a/src/roslyn/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs +++ b/src/roslyn/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs @@ -324,11 +324,23 @@ private AnalyzerConfigDocumentState GetRequiredAnalyzerConfigDocumentState(Docum /// Searches for the project state with the specified project id in the given project states. /// /// Requires the input array to be sorted by Id - private static ProjectState? GetProjectState(ImmutableArray sortedPojectStates, ProjectId projectId) + private static ProjectState? GetProjectState(ImmutableArray sortedProjectStates, ProjectId projectId) { - var index = sortedPojectStates.BinarySearch(projectId, static (projectState, projectId) => projectState.Id.CompareTo(projectId)); + var index = GetProjectStateIndex(sortedProjectStates, projectId); - return index >= 0 ? sortedPojectStates[index] : null; + return index >= 0 ? sortedProjectStates[index] : null; + } + + /// + /// Searches for the project state with the specified project id in the given project states and + /// returns it's index if found, otherwise -1. + /// + /// Requires the input array to be sorted by Id + private static int GetProjectStateIndex(ImmutableArray sortedProjectStates, ProjectId projectId) + { + var index = sortedProjectStates.BinarySearch(projectId, static (projectState, projectId) => projectState.Id.CompareTo(projectId)); + + return index >= 0 ? index : -1; } public ProjectState GetRequiredProjectState(ProjectId projectId) @@ -1170,8 +1182,9 @@ public StateChange ForkProject( { var projectId = newProjectState.Id; - Contract.ThrowIfFalse(ContainsProject(projectId)); - var newProjectStates = SortedProjectStates.Replace(oldProjectState, newProjectState); + var projectStateIndex = GetProjectStateIndex(SortedProjectStates, projectId); + Contract.ThrowIfFalse(projectStateIndex >= 0); + var newProjectStates = SortedProjectStates.SetItem(projectStateIndex, newProjectState); newDependencyGraph ??= _dependencyGraph; diff --git a/src/roslyn/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratedDocumentState.cs b/src/roslyn/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratedDocumentState.cs index a573710fcfc..4f325d28277 100644 --- a/src/roslyn/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratedDocumentState.cs +++ b/src/roslyn/src/Workspaces/Core/Portable/Workspace/Solution/SourceGeneratedDocumentState.cs @@ -47,18 +47,41 @@ public static SourceGeneratedDocumentState Create( Checksum? originalSourceTextChecksum, DateTime generationDateTime) { + return Create(documentIdentity, generatedSourceText, syntaxNode: null, parseOptions, languageServices, originalSourceTextChecksum, generationDateTime); + } + + public static SourceGeneratedDocumentState Create( + SourceGeneratedDocumentIdentity documentIdentity, + SourceText? generatedSourceText, + SyntaxNode? syntaxNode, + ParseOptions parseOptions, + LanguageServices languageServices, + Checksum? originalSourceTextChecksum, + DateTime generationDateTime) + { + Contract.ThrowIfTrue(generatedSourceText is null && syntaxNode is null); + Contract.ThrowIfTrue(generatedSourceText is not null && syntaxNode is not null); + + if (generatedSourceText is null) + { + // We don't currently support lazy source text in source generated documents, so just use the syntax to get it + Contract.ThrowIfNull(syntaxNode); + generatedSourceText = syntaxNode.GetText(); + } + // If the caller explicitly provided us with the checksum for the source text, then we always defer to that. // This happens on the host side, when we are given the data computed by the OOP side. // // If the caller didn't provide us with the checksum, then we'll compute it on demand. This happens on the OOP // side when we're actually producing the SG doc in the first place. var lazyTextChecksum = new Lazy(() => originalSourceTextChecksum ?? ComputeContentHash(generatedSourceText)); - return Create(documentIdentity, generatedSourceText, parseOptions, languageServices, lazyTextChecksum, generationDateTime); + return Create(documentIdentity, generatedSourceText, syntaxNode, parseOptions, languageServices, lazyTextChecksum, generationDateTime); } private static SourceGeneratedDocumentState Create( SourceGeneratedDocumentIdentity documentIdentity, SourceText generatedSourceText, + SyntaxNode? syntaxNode, ParseOptions parseOptions, LanguageServices languageServices, Lazy lazyTextChecksum, @@ -67,12 +90,23 @@ private static SourceGeneratedDocumentState Create( var loadTextOptions = new LoadTextOptions(generatedSourceText.ChecksumAlgorithm); var textAndVersion = TextAndVersion.Create(generatedSourceText, VersionStamp.Create()); var textSource = new ConstantTextAndVersionSource(textAndVersion); - var treeSource = CreateLazyFullyParsedTree( - textSource, - loadTextOptions, - documentIdentity.FilePath, - parseOptions, - languageServices); + + ITreeAndVersionSource treeSource; + if (syntaxNode is null) + { + treeSource = CreateLazyFullyParsedTree( + textSource, + loadTextOptions, + documentIdentity.FilePath, + parseOptions, + languageServices); + } + else + { + var factory = languageServices.GetRequiredService(); + var newTree = factory.CreateSyntaxTree(documentIdentity.FilePath, parseOptions, generatedSourceText, generatedSourceText.Encoding, generatedSourceText.ChecksumAlgorithm, syntaxNode); + treeSource = SimpleTreeAndVersionSource.Create(new TreeAndVersion(newTree, VersionStamp.Create())); + } return new SourceGeneratedDocumentState( documentIdentity, @@ -160,6 +194,7 @@ public SourceGeneratedDocumentState WithParseOptions(ParseOptions parseOptions) return Create( Identity, SourceText, + syntaxNode: null, parseOptions, LanguageServices, // We're just changing the parse options. So the checksum will remain as is. @@ -192,11 +227,22 @@ public SourceGeneratedDocumentState WithGenerationDateTime(DateTime generationDa public SourceGeneratedDocumentState WithSyntaxRoot(SyntaxNode newRoot) { // See if we can reuse this instance directly - if (this.TryGetSyntaxTree(out var tree) && tree == newRoot.SyntaxTree) + if (this.TryGetSyntaxTree(out var tree) && + tree.TryGetRoot(out var root) && + root == newRoot) + { return this; + } + + var sourceText = newRoot.GetText(); + var factory = LanguageServices.GetRequiredService(); + var newTree = factory.CreateSyntaxTree(Attributes.SyntaxTreeFilePath, ParseOptions, sourceText, sourceText.Encoding, sourceText.ChecksumAlgorithm, newRoot); + var lazyTextChecksum = new Lazy(() => ComputeContentHash(sourceText)); + var textAndVersion = TextAndVersion.Create(sourceText, VersionStamp.Create()); + var textSource = new ConstantTextAndVersionSource(textAndVersion); var newTreeVersion = GetNewTreeVersionForUpdatedTree(newRoot, GetNewerVersion(), PreservationMode.PreserveValue); - var newTreeSource = SimpleTreeAndVersionSource.Create(new TreeAndVersion(newRoot.SyntaxTree, newTreeVersion)); + var newTreeSource = SimpleTreeAndVersionSource.Create(new TreeAndVersion(newTree, newTreeVersion)); return new( this.Identity, @@ -204,11 +250,11 @@ public SourceGeneratedDocumentState WithSyntaxRoot(SyntaxNode newRoot) this.DocumentServiceProvider, this.Attributes, this.ParseOptions, - this.TextAndVersionSource, - this.SourceText, + textSource, + sourceText, this.LoadTextOptions, newTreeSource, - this._lazyContentHash, + lazyTextChecksum, this.GenerationDateTime); } diff --git a/src/roslyn/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs b/src/roslyn/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs index ed6cc9b72ee..bb335682a35 100644 --- a/src/roslyn/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs +++ b/src/roslyn/src/Workspaces/CoreTest/SolutionTests/SolutionWithSourceGeneratorTests.cs @@ -11,6 +11,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; @@ -1037,6 +1039,46 @@ public async Task WithSyntaxRootWorksOnSourceGeneratedDocument(TestHost testHost Assert.Equal("// Hello World!// Hello World!", sourceText.ToString()); } + [Theory, CombinatorialData] + public async Task WithSyntaxRootWorksOnSourceGeneratedDocument_OldCSharpVersion(TestHost testHost) + { + using var workspace = CreateWorkspaceWithPartialSemantics(testHost); + var generatorRan = false; + var analyzerReference = new TestGeneratorReference(new CallbackGenerator(_ => { }, onExecute: _ => { generatorRan = true; }, source: "// Hello World!")); + var project = AddEmptyProject(workspace.CurrentSolution) + .WithParseOptions(CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7)) + .AddAnalyzerReference(analyzerReference) + .AddDocument("RegularDocument.cs", "// Source File", filePath: "RegularDocument.cs").Project; + + // Ensure generators are ran + var objectReference = await project.GetCompilationAsync(); + + Assert.True(generatorRan); + + var generatedDocuments = await project.GetSourceGeneratedDocumentsAsync(); + var sourceGeneratedDocument = generatedDocuments.First(); + var root = await sourceGeneratedDocument.GetRequiredSyntaxRootAsync(CancellationToken.None); + + var modifiedRoot = SyntaxFactory.ParseCompilationUnit("// Changed document"); + // Default tree is the default language version + Assert.NotEqual(LanguageVersion.CSharp7, modifiedRoot.SyntaxTree.Options.LanguageVersion()); + + sourceGeneratedDocument = sourceGeneratedDocument.WithSyntaxRoot(modifiedRoot); + var sourceText = await sourceGeneratedDocument.GetTextAsync(); + Assert.Equal("// Changed document", sourceText.ToString()); + + var newTree = await sourceGeneratedDocument.GetRequiredSyntaxTreeAsync(CancellationToken.None); + Assert.Equal(LanguageVersion.CSharp7, newTree.Options.LanguageVersion()); + + generatedDocuments = await sourceGeneratedDocument.Project.GetSourceGeneratedDocumentsAsync(); + var updatedDocument = Assert.Single(generatedDocuments); + sourceText = await updatedDocument.GetTextAsync(); + Assert.Equal("// Changed document", sourceText.ToString()); + + newTree = await updatedDocument.GetRequiredSyntaxTreeAsync(CancellationToken.None); + Assert.Equal(LanguageVersion.CSharp7, newTree.Options.LanguageVersion()); + } + [Theory, CombinatorialData] public async Task WithSyntaxRootWorksOnSourceGeneratedDocument_SameRoot_Noop(TestHost testHost) { diff --git a/src/runtime/Build.proj b/src/runtime/Build.proj index 2f687610b4a..1cdf15e0e46 100644 --- a/src/runtime/Build.proj +++ b/src/runtime/Build.proj @@ -15,4 +15,40 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/runtime/Directory.Build.props b/src/runtime/Directory.Build.props index 155971eb212..7e5c028ecfa 100644 --- a/src/runtime/Directory.Build.props +++ b/src/runtime/Directory.Build.props @@ -303,6 +303,7 @@ '$(MSBuildProjectExtension)' != '.pkgproj' and '$(UsingMicrosoftNoTargetsSdk)' != 'true' and '$(UsingMicrosoftTraversalSdk)' != 'true'">true + true @@ -367,10 +368,4 @@ $(BeforeMicrosoftNETSdkTargets);$(RepositoryEngineeringDir)ILSdk.BeforeTargets.targets - - - $([MSBuild]::NormalizePath('$(ArtifactsBinDir)', 'Microsoft.NETCore.Platforms', 'runtime.json')) - $([MSBuild]::NormalizePath('$(LibrariesProjectRoot)', 'Microsoft.NETCore.Platforms', 'src', 'runtime.json')) - - diff --git a/src/runtime/Directory.Build.targets b/src/runtime/Directory.Build.targets index cd68fb94f4f..2b84a17a611 100644 --- a/src/runtime/Directory.Build.targets +++ b/src/runtime/Directory.Build.targets @@ -7,9 +7,23 @@ false + + + + + $([MSBuild]::NormalizePath('$(BootstrapRidGraphDir)', 'runtime.json')) + + $([MSBuild]::NormalizePath('$(LibrariesProjectRoot)', 'Microsoft.NETCore.Platforms', 'src', 'runtime.json')) + + + + + $([MSBuild]::NormalizePath('$(ArtifactsBinDir)', 'Microsoft.NETCore.Platforms', 'runtime.json')) + $([MSBuild]::NormalizePath('$(LibrariesProjectRoot)', 'Microsoft.NETCore.Platforms', 'src', 'runtime.json')) + + - diff --git a/src/runtime/docs/workflow/building/coreclr/cross-building.md b/src/runtime/docs/workflow/building/coreclr/cross-building.md index 6e93e7538ce..28ea2f0ef11 100644 --- a/src/runtime/docs/workflow/building/coreclr/cross-building.md +++ b/src/runtime/docs/workflow/building/coreclr/cross-building.md @@ -171,3 +171,15 @@ docker run --rm \ mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross-freebsd-12 \ ./build.sh --subset clr --cross --os freebsd ``` + +### Building CoreCLR with Bootstrapping + +CoreCLR builds a few tools, including NativeAOT compiler itself, using NativeAOT (or single file where NativeAOT is not supported). The build defaults to using a "Last Known Good" version of NativeAOT to build the tools. This "Last Known Good" version comes from the .NET SDK referenced in the global.json file. This default was chosen for a good local build experience of most repo contributors. Building with live NativeAOT version would make the local build longer and it would make debugging local changes that impact NativeAOT compiler complicated. + +The runtime's build scripts provide an additional set of options to build with the live NativeAOT version instead of the "Last Known Good" version. This is useful for testing changes to NativeAOT or the tools that are built with it, and is required for building those tools for target platforms that are not known to the "Last Known Good" version of NativeAOT, such as FreeBSD, community architectures, or non-portable builds of .NET. This is not yet implemented for Windows. + +To build the bootstrap subset of the runtime repo, you can build the `bootstrap` subset. To use the bootstrap components in the runtime repo build, you can pass the `--use-bootstrap` argument to the build script. This will use the bootstrap components instead of the "Last Known Good" version of NativeAOT. + +For simplicity, a `--bootstrap` option is also provided. This option will build the `bootstrap` subset, clean up the artifacts directory, and then build the runtime repo with the `--use-bootstrap` option. This is useful for building the runtime repo with the live NativeAOT version without having to run two separate commands. + +The `--bootstrap` option is automatically specified when building the runtime repo for .NET Source Build, as the vast majority of Source Build scenarios use non-portable RIDs. diff --git a/src/runtime/docs/workflow/building/coreclr/freebsd-instructions.md b/src/runtime/docs/workflow/building/coreclr/freebsd-instructions.md index 9ff21b3c322..cbc4dd86423 100644 --- a/src/runtime/docs/workflow/building/coreclr/freebsd-instructions.md +++ b/src/runtime/docs/workflow/building/coreclr/freebsd-instructions.md @@ -38,6 +38,8 @@ Ensure you have all of the prerequisites installed from the [Linux Requirements] Once that is done, refer to the [Linux section of the cross-building doc](/docs/workflow/building/coreclr/cross-building.md#linux-cross-building). There are detailed instructions on how to cross-compile using your Linux environment, including a section dedicated to FreeBSD building. +You'll also need to use the `--bootstrap` option as documented in the [cross-building doc](/docs/workflow/building/coreclr/cross-building.md#building-coreclr-with-bootstrapping) to build the cross-compilation toolchain. + ## Build directly on FreeBSD Ensure you have all of the prerequisites installed from the [FreeBSD Requirements](/docs/workflow/requirements/freebsd-requirements.md). diff --git a/src/runtime/eng/DotNetBuild.props b/src/runtime/eng/DotNetBuild.props deleted file mode 100644 index 80a7b1ac42a..00000000000 --- a/src/runtime/eng/DotNetBuild.props +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - $(TargetRid) - - - - - - - runtime - - .\build.cmd - ./build.sh - - minimal - - - - - - - - $(InnerBuildArgs) $(FlagParameterPrefix)restore $(FlagParameterPrefix)build $(FlagParameterPrefix)publish - $(InnerBuildArgs) $(FlagParameterPrefix)sign - $(InnerBuildArgs) $(FlagParameterPrefix)pack - - $(InnerBuildArgs) $(FlagParameterPrefix)arch $(TargetArchitecture) - $(InnerBuildArgs) $(FlagParameterPrefix)os windows - $(InnerBuildArgs) $(FlagParameterPrefix)os $(_portableOS) - - $(InnerBuildArgs) $(FlagParameterPrefix)cross - $(InnerBuildArgs) $(FlagParameterPrefix)configuration $(Configuration) - $(InnerBuildArgs) $(FlagParameterPrefix)verbosity $(LogVerbosity) - $(InnerBuildArgs) $(FlagParameterPrefix)nodereuse $(ArcadeFalseBoolBuildArg) - $(InnerBuildArgs) $(FlagParameterPrefix)warnAsError $(ArcadeFalseBoolBuildArg) - $(InnerBuildArgs) $(FlagParameterPrefix)usemonoruntime - - $(InnerBuildArgs) --outputrid $(OutputRID) - - $(InnerBuildArgs) /p:AdditionalRuntimeIdentifierParent=$(BaseOS) /p:BaseOS=$(BaseOS) - - $(InnerBuildArgs) /p:WasmEnableThreads=true - $(InnerBuildArgs) /p:MonoEnableLLVM=$(MonoEnableLLVM) - $(InnerBuildArgs) /p:MonoAOTEnableLLVM=$(MonoAOTEnableLLVM) - $(InnerBuildArgs) /p:MonoBundleLLVMOptimizer=$(MonoBundleLLVMOptimizer) - $(InnerBuildArgs) /p:DotNetBuildAllRuntimePacks=$(DotNetBuildAllRuntimePacks) - $(InnerBuildArgs) /p:DotNetBuildPass=$(DotNetBuildPass) - $(InnerBuildArgs) $(FlagParameterPrefix)pgoinstrument - - - $(InnerBuildArgs) /p:DotNetBuildRepo=true - $(InnerBuildArgs) /p:DotNetBuildOrchestrator=true - $(InnerBuildArgs) /p:OfficialBuildId=$(OfficialBuildId) - $(InnerBuildArgs) /p:ContinuousIntegrationBuild=$(ContinuousIntegrationBuild) - $(InnerBuildArgs) /p:PortableBuild=$(PortableBuild) - $(InnerBuildArgs) /p:RestoreConfigFile=$(RestoreConfigFile) - $(InnerBuildArgs) /p:ForceDryRunSigning=$(ForceDryRunSigning) - $(InnerBuildArgs) /p:DefaultArtifactVisibility=$(DefaultArtifactVisibility) - $(InnerBuildArgs) /p:DotNetEsrpToolPath=$(DotNetEsrpToolPath) - $(InnerBuildArgs) /p:DotNetBuildTests=$(DotNetBuildTests) - $(InnerBuildArgs) /p:PublishingVersion=$(PublishingVersion) - $(InnerBuildArgs) /p:RepositoryUrl=$(RepositoryUrl) - - - $(InnerBuildArgs) /p:SourceBuiltAssetsDir=$(SourceBuiltAssetsDir) - $(InnerBuildArgs) /p:SourceBuiltShippingPackagesDir=$(SourceBuiltShippingPackagesDir) - $(InnerBuildArgs) /p:SourceBuiltNonShippingPackagesDir=$(SourceBuiltNonShippingPackagesDir) - $(InnerBuildArgs) /p:SourceBuiltAssetManifestsDir=$(SourceBuiltAssetManifestsDir) - $(InnerBuildArgs) /p:SourceBuiltPdbArtifactsDir=$(SourceBuiltPdbArtifactsDir) - $(InnerBuildArgs) /p:SourceBuiltSymbolsDir=$(SourceBuiltSymbolsDir) - $(InnerBuildArgs) /p:GitHubRepositoryName=$(GitHubRepositoryName) - - - +$(UseSystemLibs) - $(InnerBuildArgs) --cmakeargs -DCLR_CMAKE_USE_SYSTEM_BROTLI=true - $(InnerBuildArgs) --cmakeargs -DCLR_CMAKE_USE_SYSTEM_LIBUNWIND=true - - - $(InnerBuildArgs) --cmakeargs -DCLR_CMAKE_USE_SYSTEM_RAPIDJSON=true - $(InnerBuildArgs) --cmakeargs -DCLR_CMAKE_USE_SYSTEM_ZLIB=true - $(InnerBuildArgs) /p:FeatureXplatEventSource=false - - - $(InnerBuildArgs) /p:NetCoreAppToolCurrentVersion=$(NetCoreAppToolCurrentVersion) - - $(InnerBuildArgs) /p:EnableDefaultRidSpecificArtifacts=$(EnableDefaultRidSpecificArtifacts) - - - - - - - runtime - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/runtime/eng/Publishing.props b/src/runtime/eng/Publishing.props index 8400bbabe0e..2d8c002fa34 100644 --- a/src/runtime/eng/Publishing.props +++ b/src/runtime/eng/Publishing.props @@ -43,7 +43,7 @@ - + + - - <_portableOS>$(TargetOS.ToLowerInvariant()) - <_portableOS Condition="'$(_portableOS)' == 'windows'">win + $(TargetOS.ToLowerInvariant()) + win - <_portableOS Condition="'$(_portableOS)' == 'anyos'">$(__PortableTargetOS) + $(__PortableTargetOS) - <_portableOS Condition="'$(_portableOS)' == 'linux' and '$(__PortableTargetOS)' == 'linux-musl'">linux-musl - <_portableOS Condition="'$(_portableOS)' == 'linux' and '$(__PortableTargetOS)' == 'linux-bionic'">linux-bionic + linux-musl + linux-bionic - <_portableOS Condition="'$(HostOS)' == 'win' and '$(TargetsMobile)' != 'true'">win + win @@ -38,7 +38,7 @@ <_distroRidIndex>$(_parseDistroRid.LastIndexOf('-')) <_outputOS>$(_parseDistroRid.SubString(0, $(_distroRidIndex))) - <_outputOS Condition="'$(PortableBuild)' == 'true'">$(_portableOS) + <_outputOS Condition="'$(PortableBuild)' == 'true'">$(PortableOS) $(_outputOS)-$(TargetArchitecture) @@ -49,8 +49,8 @@ true true true - true - true + true + true true true true diff --git a/src/runtime/eng/Subsets.props b/src/runtime/eng/Subsets.props index 983fcec2306..96c5cf47659 100644 --- a/src/runtime/eng/Subsets.props +++ b/src/runtime/eng/Subsets.props @@ -51,10 +51,13 @@ <_NativeAotSupportedArch Condition="'$(TargetArchitecture)' == 'x64' or '$(TargetArchitecture)' == 'arm64' or '$(TargetArchitecture)' == 'arm' or '$(TargetArchitecture)' == 'loongarch64' or '$(TargetArchitecture)' == 'riscv64' or ('$(TargetOS)' == 'windows' and '$(TargetArchitecture)' == 'x86')">true true - - <_AotToolsSupportedOS Condition="'$(TargetsMobile)' != 'true' and '$(TargetsLinuxBionic)' != 'true' and '$(StageOneBuild)' != 'true'">true - <_AotToolsSupportedArch Condition="'$(TargetArchitecture)' != 'armel'">true - true + + <_SdkToolsSupportedOS Condition="'$(TargetsMobile)' != 'true' and '$(TargetsLinuxBionic)' != 'true'">true + <_SdkToolsSupportedArch Condition="'$(TargetArchitecture)' != 'armel'">true + true + + <_UseNativeAotForComponentsCrossOS Condition="'$(CrossBuild)' == 'true' and '$(_hostArchitecture)' == '$(_targetArchitecture)' and '$(_hostOS)' != 'windows'">true + true @@ -149,6 +152,12 @@ $(DefaultPacksSubsets)+packs.installers $(DefaultPacksSubsets)+packs.tests $(DefaultPacksSubsets)+mono.manifests + + host.native+libs.sfx+libs.pretest + $(BootstrapSubsets)+clr.runtime+clr.corelib + $(BootstrapSubsets)+clr.nativeaotlibs+clr.nativeaotruntime+libs.native + + true @@ -160,6 +169,7 @@ <_subset>$(_subset.Replace('+tools+', '+$(DefaultToolsSubsets)+')) <_subset>$(_subset.Replace('+host+', '+$(DefaultHostSubsets)+')) <_subset>$(_subset.Replace('+packs+', '+$(DefaultPacksSubsets)+')) + <_subset>$(_subset.Replace('+bootstrap+', '+bootstrap+$(BootstrapSubsets)+')) <_subset Condition="'$(TargetOS)' == 'browser'">$(_subset.Replace('+clr.runtime+', '+mono.emsdk+clr.runtime+')) @@ -170,8 +180,6 @@ - <_IsCommunityCrossArchitecture Condition="'$(CrossBuild)' == 'true' and ('$(TargetArchitecture)' == 'loongarch64' or '$(TargetArchitecture)' == 'riscv64')">true - true true @@ -259,6 +267,7 @@ + @@ -441,22 +450,22 @@ $(CoreClrProjectRoot)tools\PdbChecker\PdbChecker.csproj; $(CoreClrProjectRoot)tools\AssemblyChecker\AssemblyChecker.csproj; $(ToolsProjectRoot)StressLogAnalyzer\src\StressLogAnalyzer.csproj" Category="clr" Condition="'$(DotNetBuildSourceOnly)' != 'true'"/> - - - - - - - - - - - - + + + + + + + + + + + + + @@ -724,6 +733,11 @@ + + + + + diff --git a/src/runtime/eng/Version.Details.xml b/src/runtime/eng/Version.Details.xml index 0b6c06759ee..b81ca11f9be 100644 --- a/src/runtime/eng/Version.Details.xml +++ b/src/runtime/eng/Version.Details.xml @@ -1,5 +1,5 @@ - + https://github.com/dotnet/icu @@ -41,91 +41,91 @@ https://github.com/dotnet/llvm-project da5dd054a531e6fea65643b7e754285b73eab433 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 https://github.com/dotnet/runtime-assets @@ -263,33 +263,33 @@ https://github.com/dotnet/llvm-project da5dd054a531e6fea65643b7e754285b73eab433 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 https://github.com/dotnet/xharness @@ -303,9 +303,9 @@ https://github.com/dotnet/xharness 6702e80281066daa33390d759263823298486439 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -351,9 +351,9 @@ https://github.com/dotnet/roslyn-analyzers cbcc6ddf3db6dedff5049f0397e1351951c13271 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/src/runtime/eng/Versions.props b/src/runtime/eng/Versions.props index 097ec98aab7..28ef05acdce 100644 --- a/src/runtime/eng/Versions.props +++ b/src/runtime/eng/Versions.props @@ -83,34 +83,34 @@ 0.2.0 - 10.0.100-preview.5.25229.109 + 10.0.100-preview.5.25251.102 - 10.0.0-beta.25229.109 - 10.0.0-beta.25229.109 - 10.0.0-beta.25229.109 - 10.0.0-beta.25229.109 - 2.9.2-beta.25229.109 - 10.0.0-beta.25229.109 - 2.9.2-beta.25229.109 - 10.0.0-beta.25229.109 - 10.0.0-beta.25229.109 - 10.0.0-beta.25229.109 - 10.0.0-beta.25229.109 - 10.0.0-beta.25229.109 - 10.0.0-beta.25229.109 - 10.0.0-beta.25229.109 - 10.0.0-beta.25229.109 - 10.0.0-beta.25229.109 + 10.0.0-beta.25251.102 + 10.0.0-beta.25251.102 + 10.0.0-beta.25251.102 + 10.0.0-beta.25251.102 + 2.9.2-beta.25251.102 + 10.0.0-beta.25251.102 + 2.9.2-beta.25251.102 + 10.0.0-beta.25251.102 + 10.0.0-beta.25251.102 + 10.0.0-beta.25251.102 + 10.0.0-beta.25251.102 + 10.0.0-beta.25251.102 + 10.0.0-beta.25251.102 + 10.0.0-beta.25251.102 + 10.0.0-beta.25251.102 + 10.0.0-beta.25251.102 1.4.0 6.0.0-preview.1.102 - 10.0.0-preview.5.25229.109 + 10.0.0-preview.5.25251.102 6.0.0 - 10.0.0-preview.5.25229.109 - 10.0.0-preview.5.25229.109 + 10.0.0-preview.5.25251.102 + 10.0.0-preview.5.25251.102 6.0.0 4.6.1 @@ -128,16 +128,16 @@ 8.0.0 8.0.1 5.0.0 - 10.0.0-preview.5.25229.109 - 10.0.0-preview.5.25229.109 + 10.0.0-preview.5.25251.102 + 10.0.0-preview.5.25251.102 6.0.0 5.0.0 5.0.0 5.0.0 7.0.0 - 10.0.0-preview.5.25229.109 + 10.0.0-preview.5.25251.102 7.0.0 - 10.0.0-preview.5.25229.109 + 10.0.0-preview.5.25251.102 8.0.0 4.5.1 @@ -180,7 +180,7 @@ 2.0.0 17.10.0-beta1.24272.1 - 2.0.0-beta5.25229.109 + 2.0.0-beta5.25251.102 3.1.16 2.1.0 2.0.3 @@ -226,7 +226,7 @@ 9.0.0-preview-20241010.1 - 0.11.5-alpha.25229.109 + 0.11.5-alpha.25251.102 10.0.0-preview.5.25227.1 @@ -258,7 +258,7 @@ Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-10_0_100_Transport --> - 10.0.100-preview.5.25229.109 + 10.0.100-preview.5.25251.102 $(MicrosoftNETWorkloadEmscriptenCurrentManifest100100TransportVersion) 1.1.87-gba258badda diff --git a/src/runtime/eng/build.sh b/src/runtime/eng/build.sh index a4e36af19ee..6a82dc2cbb9 100755 --- a/src/runtime/eng/build.sh +++ b/src/runtime/eng/build.sh @@ -48,6 +48,8 @@ usage() echo " --usemonoruntime Product a .NET runtime with Mono as the underlying runtime." echo " --verbosity (-v) MSBuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]." echo " [Default: Minimal]" + echo " --use-bootstrap Use the results of building the bootstrap subset to build published tools on the target machine." + echo " --bootstrap Build the bootstrap subset and then build the repo with --use-bootstrap." echo "" echo "Actions (defaults to --restore --build):" @@ -156,6 +158,7 @@ cmakeargs='' extraargs='' crossBuild=0 portableBuild=1 +bootstrap=0 source $scriptroot/common/native/init-os-and-arch.sh @@ -508,6 +511,16 @@ while [[ $# > 0 ]]; do shift 1 ;; + -use-bootstrap) + arguments="$arguments /p:UseBootstrap=true" + shift 1 + ;; + + -bootstrap) + bootstrap=1 + shift 1 + ;; + -fsanitize) if [ -z ${2+x} ]; then echo "No value for -fsanitize is supplied. See help (--help) for supported values." 1>&2 @@ -570,4 +583,21 @@ export DOTNETSDK_ALLOW_TARGETING_PACK_CACHING=0 cmakeargs="${cmakeargs// /%20}" arguments="$arguments /p:TargetArchitecture=$arch /p:BuildArchitecture=$hostArch" arguments="$arguments /p:CMakeArgs=\"$cmakeargs\" $extraargs" + +if [[ "$bootstrap" == "1" ]]; then + # Strip build actions other than -restore and -build from the arguments for the bootstrap build. + bootstrapArguments="$arguments" + for flag in --sign --publish --pack --test -sign -publish -pack -test; do + bootstrapArguments="${bootstrapArguments//$flag/}" + done + "$scriptroot/common/build.sh" $bootstrapArguments /p:Subset=bootstrap -bl:$scriptroot/../artifacts/log/bootstrap.binlog + + # Remove artifacts from the bootstrap build so the product build is a "clean" build. + echo "Cleaning up artifacts from bootstrap build..." + rm -r "$scriptroot/../artifacts/bin" + # Remove all directories in obj except for the source-built-upstream-cache directory to avoid breaking SourceBuild. + find "$scriptroot/../artifacts/obj" -mindepth 1 -maxdepth 1 ! -name 'source-built-upstream-cache' -exec rm -rf {} + + arguments="$arguments /p:UseBootstrap=true" +fi + "$scriptroot/common/build.sh" $arguments diff --git a/src/runtime/eng/common/core-templates/jobs/source-build.yml b/src/runtime/eng/common/core-templates/jobs/source-build.yml index a10ccfbee6d..df24c948ba1 100644 --- a/src/runtime/eng/common/core-templates/jobs/source-build.yml +++ b/src/runtime/eng/common/core-templates/jobs/source-build.yml @@ -14,7 +14,7 @@ parameters: # This is the default platform provided by Arcade, intended for use by a managed-only repo. defaultManagedPlatform: name: 'Managed' - container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream9' + container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream-10-amd64' # Defines the platforms on which to run build jobs. One job is created for each platform, and the # object in this array is sent to the job template as 'platform'. If no platforms are specified, diff --git a/src/runtime/eng/common/core-templates/steps/source-build.yml b/src/runtime/eng/common/core-templates/steps/source-build.yml index 8c88ccd7b08..c6b9ef51ac6 100644 --- a/src/runtime/eng/common/core-templates/steps/source-build.yml +++ b/src/runtime/eng/common/core-templates/steps/source-build.yml @@ -121,14 +121,3 @@ steps: continueOnError: true condition: succeededOrFailed() sbomEnabled: false # we don't need SBOM for logs - -# Manually inject component detection so that we can ignore the source build upstream cache, which contains -# a nupkg cache of input packages (a local feed). -# This path must match the upstream cache path in property 'CurrentRepoSourceBuiltNupkgCacheDir' -# in src\Microsoft.DotNet.Arcade.Sdk\tools\SourceBuild\SourceBuildArcade.targets -- template: /eng/common/core-templates/steps/component-governance.yml - parameters: - displayName: Component Detection (Exclude upstream cache) - is1ESPipeline: ${{ parameters.is1ESPipeline }} - componentGovernanceIgnoreDirectories: '$(Build.SourcesDirectory)/artifacts/sb/src/artifacts/obj/source-built-upstream-cache' - disableComponentGovernance: ${{ eq(variables['System.TeamProject'], 'public') }} diff --git a/src/runtime/eng/liveBuilds.targets b/src/runtime/eng/liveBuilds.targets index 4155aa5f59f..50267c114cf 100644 --- a/src/runtime/eng/liveBuilds.targets +++ b/src/runtime/eng/liveBuilds.targets @@ -56,9 +56,22 @@ x64 - - $([MSBuild]::NormalizePath('$(DotNetHostBinDir)', 'apphost$(ExeSuffix)')) - $([MSBuild]::NormalizePath('$(CoreCLRArtifactsPath)', 'corehost', 'singlefilehost$(ExeSuffix)')) + + $(ArtifactsDir)bootstrap/microsoft.netcore.app/ref + $(ArtifactsDir)bootstrap/microsoft.netcore.app/lib + $(ArtifactsDir)bootstrap/aotsdk + $(ArtifactsDir)bootstrap/host + $(ArtifactsDir)bootstrap/ridgraph + + + + $([MSBuild]::NormalizePath('$(DotNetHostBinDir)', 'apphost$(ExeSuffix)')) + $([MSBuild]::NormalizePath('$(CoreCLRArtifactsPath)', 'corehost', 'singlefilehost$(ExeSuffix)')) + + + + $(BootstrapHostDir)/apphost$(ExeSuffix) + $(BootstrapHostDir)/singlefilehost$(ExeSuffix) diff --git a/src/runtime/eng/pipelines/runtime-linker-tests.yml b/src/runtime/eng/pipelines/runtime-linker-tests.yml index 712890ffe1c..9df8042e7af 100644 --- a/src/runtime/eng/pipelines/runtime-linker-tests.yml +++ b/src/runtime/eng/pipelines/runtime-linker-tests.yml @@ -103,7 +103,7 @@ extends: or( eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_non_mono_and_wasm.containsChange'], true), eq(variables['isRollingBuild'], true)) - buildArgs: -s clr+libs+tools.illink -c $(_BuildConfig) + buildArgs: -s clr+libs+tools.illink+host.native -c $(_BuildConfig) postBuildSteps: - template: /eng/pipelines/libraries/execute-trimming-tests-steps.yml diff --git a/src/runtime/eng/pipelines/runtime.yml b/src/runtime/eng/pipelines/runtime.yml index 292deb03813..5e6ac75cd59 100644 --- a/src/runtime/eng/pipelines/runtime.yml +++ b/src/runtime/eng/pipelines/runtime.yml @@ -504,27 +504,9 @@ extends: - linux_loongarch64 jobParameters: testScope: innerloop - nameSuffix: CoreCLR_TwoStage - buildArgs: -s clr+libs+host -c $(_BuildConfig) -rc Checked -p:StageOneBuild=true + nameSuffix: CoreCLR_Bootstrapped + buildArgs: -s clr+libs+host -c $(_BuildConfig) -rc Checked --bootstrap timeoutInMinutes: 120 - postBuildSteps: - - script: | - echo Running $(Build.SourcesDirectory)/build$(scriptExt) \ - ${{ variables.debugOnPrReleaseOnRolling }} \ - -s clr.tools+packs -rc Checked -cross \ - -os $(osGroup) \ - -a $(archType) \ - -c $(_BuildConfig) \ - -p:StageTwoBuild=true - - $(Build.SourcesDirectory)/build$(scriptExt) \ - ${{ variables.debugOnPrReleaseOnRolling }} \ - -s clr.tools+packs -rc Checked -cross \ - -os $(osGroup) \ - -a $(archType) \ - -c $(_BuildConfig) \ - -p:StageTwoBuild=true - displayName: Build clr.tools and packs condition: >- or( eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), diff --git a/src/runtime/eng/targetingpacks.targets b/src/runtime/eng/targetingpacks.targets index 4e0fce1e532..203a2921f25 100644 --- a/src/runtime/eng/targetingpacks.targets +++ b/src/runtime/eng/targetingpacks.targets @@ -34,6 +34,7 @@ $(UseLocalTargetingRuntimePack) $(UseLocalTargetingRuntimePack) + $(UseLocalTargetingRuntimePack) @@ -113,21 +114,30 @@ + + $(MicrosoftNetCoreAppRefPackDir) + $(MicrosoftNetCoreAppRuntimePackDir) + + + $(BootstrapRefPackDir) + $(BootstrapRuntimePackDir) + + + Condition="!Exists('$(LocalRefPackDir)\data\FrameworkList.xml')" /> - - - - $(MicrosoftNetCoreAppRuntimePackDir) + $(LocalRuntimePackDir) @@ -146,6 +156,10 @@ + + $(LocalAppHostPath) + $(LocalSingleFileHostPath) + - $(ProductVersion) - $(BundledNETCoreAppPackageVersion) + $(ProductVersion) + + + $(CoreCLRCrossILCompilerDir) + $(ROOTFS_DIR) + $(CoreCLRILCompilerDir)netstandard/ILCompiler.Build.Tasks.dll + $(CoreCLRAotSdkDir) + $(MicrosoftNetCoreAppRuntimePackRidLibTfmDir) + $(MicrosoftNetCoreAppRuntimePackNativeDir) + + + + $(BootstrapRuntimePackDir)/runtimes/$(OutputRID)/lib/$(NetCoreAppCurrent)/ + $(BootstrapRuntimePackDir)/runtimes/$(OutputRID)/native/ + $(BootstrapAotSdkDir)/ + diff --git a/src/runtime/eng/testing/linker/project.csproj.template b/src/runtime/eng/testing/linker/project.csproj.template index 3dc1d265454..7498d355dfc 100644 --- a/src/runtime/eng/testing/linker/project.csproj.template +++ b/src/runtime/eng/testing/linker/project.csproj.template @@ -25,8 +25,6 @@ {NetCoreAppMaximumVersion} {UseMonoRuntime} {RuntimeIdentifier} - {AppHostSourcePath} - {SingleFileHostSourcePath} true @@ -48,20 +46,22 @@ {ProductVersion} {NetCoreAppCurrent} {NetCoreAppCurrentVersion} + {LocalAppHostPath} + {LocalSingleFileHostPath} {MicrosoftNetCoreAppFrameworkName} {MicrosoftNetCoreAppRefPackDir} {MicrosoftNetCoreAppRuntimePackDir} + {MicrosoftNetCoreAppRuntimePackRidLibTfmDir} + {MicrosoftNetCoreAppRuntimePackNativeDir} + {CoreCLRILCompilerDir} + {CoreCLRCrossILCompilerDir} + {CoreCLRAotSdkDir} {RepositoryEngineeringDir} <_ExtraTrimmerArgs>{ExtraTrimmerArgs} $(_ExtraTrimmerArgs) --dump-dependencies {AdditionalProperties} - {IlcToolsPath} - {IlcBuildTasksPath} - {IlcSdkPath} - {IlcFrameworkPath} - {IlcFrameworkNativePath} {CoreCLRBuildIntegrationDir} diff --git a/src/runtime/eng/testing/linker/trimmingTests.targets b/src/runtime/eng/testing/linker/trimmingTests.targets index 7919cdab568..a4845dd24f6 100644 --- a/src/runtime/eng/testing/linker/trimmingTests.targets +++ b/src/runtime/eng/testing/linker/trimmingTests.targets @@ -100,11 +100,6 @@ .Replace('{ExtraTrimmerArgs}', '%(TestConsoleApps.ExtraTrimmerArgs)') .Replace('{AdditionalProperties}', '$(_additionalPropertiesString)') .Replace('{ToolsILLinkDir}', '$(ToolsILLinkDir)') - .Replace('{IlcToolsPath}', '$(IlcToolsPath)') - .Replace('{IlcBuildTasksPath}', '$(CoreCLRILCompilerDir)netstandard/ILCompiler.Build.Tasks.dll') - .Replace('{IlcSdkPath}', '$(CoreCLRAotSdkDir)') - .Replace('{IlcFrameworkPath}', '$(MicrosoftNetCoreAppRuntimePackRidLibTfmDir)') - .Replace('{IlcFrameworkNativePath}', '$(MicrosoftNetCoreAppRuntimePackNativeDir)') .Replace('{CoreCLRBuildIntegrationDir}', '$(CoreCLRBuildIntegrationDir)') .Replace('{RuntimeHostConfigurationOptions}', '$(_runtimeHostConfigurationOptionsString)') .Replace('{AdditionalProjectReferences}', '$(_additionalProjectReferencesString)') @@ -125,9 +120,14 @@ .Replace('{MicrosoftNetCoreAppFrameworkName}', '$(MicrosoftNetCoreAppFrameworkName)') .Replace('{MicrosoftNetCoreAppRefPackDir}', '$(MicrosoftNetCoreAppRefPackDir)') .Replace('{MicrosoftNetCoreAppRuntimePackDir}', '$(MicrosoftNetCoreAppRuntimePackDir)') + .Replace('{MicrosoftNetCoreAppRuntimePackRidLibTfmDir}', '$(MicrosoftNetCoreAppRuntimePackRidLibTfmDir)') + .Replace('{MicrosoftNetCoreAppRuntimePackNativeDir}', '$(MicrosoftNetCoreAppRuntimePackNativeDir)') + .Replace('{CoreCLRILCompilerDir}', '$(CoreCLRILCompilerDir)') + .Replace('{CoreCLRCrossILCompilerDir}', '$(CoreCLRCrossILCompilerDir)') + .Replace('{CoreCLRAotSdkDir}', '$(CoreCLRAotSdkDir)') .Replace('{NativeSanitizersTargets}', '$(RepositoryEngineeringDir)nativeSanitizers.targets') - .Replace('{AppHostSourcePath}', '$(AppHostSourcePath)') - .Replace('{SingleFileHostSourcePath}', '$(SingleFileHostSourcePath)') + .Replace('{LocalAppHostPath}', '$(LocalAppHostPath)') + .Replace('{LocalSingleFileHostPath}', '$(LocalSingleFileHostPath)') .Replace('{SanitizerRuntimeFolder}', '$(DotNetHostBinDir)'))" Overwrite="true" /> - $(CoreCLRCrossILCompilerDir) - $(ROOTFS_DIR) - $(CoreCLRILCompilerDir)netstandard/ILCompiler.Build.Tasks.dll - $(CoreCLRAotSdkDir) - $(NetCoreAppCurrentTestHostSharedFrameworkPath) - $(NetCoreAppCurrentTestHostSharedFrameworkPath) module compiled with /GL found $(NoWarn);IL1005;IL2122;IL3000;IL3001;IL3002;IL3003;IL3050;IL3051;IL3052;IL3053 partial diff --git a/src/runtime/eng/toolAot.targets b/src/runtime/eng/toolAot.targets index f692cf10998..21b633b596d 100644 --- a/src/runtime/eng/toolAot.targets +++ b/src/runtime/eng/toolAot.targets @@ -12,15 +12,19 @@ true - - - true + + <_TrueTargetRid>$(RuntimeIdentifier) + + $(BaseOS) + + + + $(_TrueTargetRid) - - - - (RuntimeTypeHandle.InternalAllocNoChecks((RuntimeType)GetType())); + MulticastDelegate result = Unsafe.As(RuntimeTypeHandle.InternalAllocNoChecks(RuntimeHelpers.GetMethodTable(this))); // Performance optimization - if this already points to a true multicast delegate, // copy _methodPtr and _methodPtrAux fields rather than calling into the EE to get them diff --git a/src/runtime/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs b/src/runtime/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs index a441e4890f9..e30e94eaf41 100644 --- a/src/runtime/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs +++ b/src/runtime/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs @@ -517,6 +517,45 @@ private static void ArrayTypeCheck_Helper(object obj, void* elementType) } } + // Helpers for boxing + [DebuggerHidden] + internal static object? Box_Nullable(MethodTable* srcMT, ref byte nullableData) + { + Debug.Assert(srcMT->IsNullable); + + if (nullableData == 0) + return null; + + // Allocate a new instance of the T in Nullable. + MethodTable* dstMT = srcMT->InstantiationArg0(); + ref byte srcValue = ref Unsafe.Add(ref nullableData, srcMT->NullableValueAddrOffset); + + // Delegate to non-nullable boxing implementation + return Box(dstMT, ref srcValue); + } + + [DebuggerHidden] + internal static object Box(MethodTable* typeMT, ref byte unboxedData) + { + Debug.Assert(typeMT != null); + Debug.Assert(typeMT->IsValueType); + + // A null can be passed for boxing of a null ref. + _ = Unsafe.ReadUnaligned(ref unboxedData); + + object boxed = RuntimeTypeHandle.InternalAllocNoChecks(typeMT); + if (typeMT->ContainsGCPointers) + { + Buffer.BulkMoveWithWriteBarrier(ref boxed.GetRawData(), ref unboxedData, typeMT->GetNumInstanceFieldBytesIfContainsGCPointers()); + } + else + { + SpanHelpers.Memmove(ref boxed.GetRawData(), ref unboxedData, typeMT->GetNumInstanceFieldBytes()); + } + + return boxed; + } + // Helpers for Unboxing #if FEATURE_TYPEEQUIVALENCE [DebuggerHidden] @@ -615,27 +654,8 @@ internal static void Unbox_Nullable(ref byte destPtr, MethodTable* typeMT, objec [DebuggerHidden] internal static object? ReboxFromNullable(MethodTable* srcMT, object src) { - Debug.Assert(srcMT->IsNullable); - ref byte nullableData = ref src.GetRawData(); - - // If 'hasValue' is false, return null. - if (!Unsafe.As(ref nullableData)) - return null; - - // Allocate a new instance of the T in Nullable. - MethodTable* dstMT = srcMT->InstantiationArg0(); - object dst = RuntimeTypeHandle.InternalAlloc(dstMT); - - // Copy data from the Nullable. - ref byte srcData = ref Unsafe.Add(ref nullableData, srcMT->NullableValueAddrOffset); - ref byte dstData = ref RuntimeHelpers.GetRawData(dst); - if (dstMT->ContainsGCPointers) - Buffer.BulkMoveWithWriteBarrier(ref dstData, ref srcData, dstMT->GetNumInstanceFieldBytesIfContainsGCPointers()); - else - SpanHelpers.Memmove(ref dstData, ref srcData, dstMT->GetNumInstanceFieldBytes()); - - return dst; + return Box_Nullable(srcMT, ref nullableData); } [DebuggerHidden] diff --git a/src/runtime/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs b/src/runtime/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs index 629774bd0df..2f4a401b18a 100644 --- a/src/runtime/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs +++ b/src/runtime/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs @@ -445,8 +445,8 @@ internal static unsafe bool ObjectHasComponentSize(object obj) /// A reference to the data to box. /// A boxed instance of the value at . /// This method includes proper handling for nullable value types as well. - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern unsafe object? Box(MethodTable* methodTable, ref byte data); + internal static unsafe object? Box(MethodTable* methodTable, ref byte data) => + methodTable->IsNullable ? CastHelpers.Box_Nullable(methodTable, ref data) : CastHelpers.Box(methodTable, ref data); // Given an object reference, returns its MethodTable*. // diff --git a/src/runtime/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs b/src/runtime/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs index 436074cf242..e1bc5e6a094 100644 --- a/src/runtime/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs +++ b/src/runtime/src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs @@ -58,9 +58,14 @@ class AsmOffsets #if TARGET_64BIT public const int OFFSETOF__REGDISPLAY__m_pCurrentContext = 0x8; +#if FEATURE_INTERPRETER + public const int SIZEOF__StackFrameIterator = 0x170; + public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0x168; +#else public const int SIZEOF__StackFrameIterator = 0x150; - public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0x132; public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0x148; +#endif + public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0x132; #elif TARGET_X86 public const int OFFSETOF__REGDISPLAY__m_pCurrentContext = 0x4; public const int SIZEOF__StackFrameIterator = 0x3cc; @@ -119,9 +124,14 @@ class AsmOffsets #if TARGET_64BIT public const int OFFSETOF__REGDISPLAY__m_pCurrentContext = 0x8; +#if FEATURE_INTERPRETER + public const int SIZEOF__StackFrameIterator = 0x168; + public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0x160; +#else public const int SIZEOF__StackFrameIterator = 0x148; - public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0x12a; public const int OFFSETOF__StackFrameIterator__m_AdjustedControlPC = 0x140; +#endif + public const int OFFSETOF__StackFrameIterator__m_isRuntimeWrappedExceptions = 0x12a; #elif TARGET_X86 public const int OFFSETOF__REGDISPLAY__m_pCurrentContext = 0x4; public const int SIZEOF__StackFrameIterator = 0x3c4; diff --git a/src/runtime/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/runtime/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs index 8e03b99165d..b8ae179ff25 100644 --- a/src/runtime/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/runtime/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -299,25 +299,27 @@ internal static object InternalAlloc(RuntimeType type) [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_InternalAlloc")] private static unsafe partial void InternalAlloc(MethodTable* pMT, ObjectHandleOnStack result); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static object InternalAllocNoChecks(MethodTable* pMT) { - object? result = null; - InternalAllocNoChecks(pMT, ObjectHandleOnStack.Create(ref result)); - return result!; - } + return InternalAllocNoChecks_FastPath(pMT) ?? InternalAllocNoChecksWorker(pMT); - internal static object InternalAllocNoChecks(RuntimeType type) - { - Debug.Assert(!type.GetNativeTypeHandle().IsTypeDesc); - object? result = null; - InternalAllocNoChecks(type.GetNativeTypeHandle().AsMethodTable(), ObjectHandleOnStack.Create(ref result)); - GC.KeepAlive(type); - return result!; + [MethodImpl(MethodImplOptions.NoInlining)] + static object InternalAllocNoChecksWorker(MethodTable* pMT) + { + object? result = null; + InternalAllocNoChecks(pMT, ObjectHandleOnStack.Create(ref result)); + return result!; + } } [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_InternalAllocNoChecks")] private static unsafe partial void InternalAllocNoChecks(MethodTable* pMT, ObjectHandleOnStack result); + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern object? InternalAllocNoChecks_FastPath(MethodTable* pMT); + /// /// Given a RuntimeType, returns information about how to activate it via calli /// semantics. This method will ensure the type object is fully initialized within diff --git a/src/runtime/src/coreclr/clr.featuredefines.props b/src/runtime/src/coreclr/clr.featuredefines.props index 5dd3516f862..883d0bda0f5 100644 --- a/src/runtime/src/coreclr/clr.featuredefines.props +++ b/src/runtime/src/coreclr/clr.featuredefines.props @@ -26,6 +26,10 @@ true + + true + + $(DefineConstants);FEATURE_COMWRAPPERS $(DefineConstants);FEATURE_COMINTEROP @@ -36,6 +40,7 @@ $(DefineConstants);FEATURE_EVENTSOURCE_XPLAT $(DefineConstants);FEATURE_TYPEEQUIVALENCE $(DefineConstants);FEATURE_EH_FUNCLETS + $(DefineConstants);FEATURE_INTERPRETER $(DefineConstants);PROFILING_SUPPORTED diff --git a/src/runtime/src/coreclr/debug/di/cordb.cpp b/src/runtime/src/coreclr/debug/di/cordb.cpp index 9f8a6f49e74..d83d9f92102 100644 --- a/src/runtime/src/coreclr/debug/di/cordb.cpp +++ b/src/runtime/src/coreclr/debug/di/cordb.cpp @@ -321,19 +321,6 @@ STDAPI DLLEXPORT DllGetClassObjectInternal( // Return code. { pfnCreateObject = Cordb::CreateObjectTelesto; } -#else // !FEATURE_DBGIPC_TRANSPORT_DI - if(rclsid == CLSID_CorDebug_V1) - { - if (0) // if (IsSingleCLR()) - { - // Don't allow creating backwards objects until we ensure that the v2.0 Right-side - // is backwards compat. This may involve using CordbProcess::SupportsVersion to conditionally - // emulate old behavior. - // If emulating V1.0, QIs for V2.0 interfaces should fail. - _ASSERTE(!"Ensure that V2.0 RS is backwards compat"); - pfnCreateObject = Cordb::CreateObjectV1; - } - } #endif // FEATURE_DBGIPC_TRANSPORT_DI if (pfnCreateObject == NULL) diff --git a/src/runtime/src/coreclr/debug/di/rsmain.cpp b/src/runtime/src/coreclr/debug/di/rsmain.cpp index d717b30a548..56a9a1557d6 100644 --- a/src/runtime/src/coreclr/debug/di/rsmain.cpp +++ b/src/runtime/src/coreclr/debug/di/rsmain.cpp @@ -2028,11 +2028,6 @@ void Cordb::EnsureCanLaunchOrAttach(BOOL fWin32DebuggingEnabled) // Made it this far, we succeeded. } -HRESULT Cordb::CreateObjectV1(REFIID id, void **object) -{ - return CreateObject(CorDebugVersion_1_0, ProcessDescriptor::UNINITIALIZED_PID, NULL, NULL, id, object); -} - #if defined(FEATURE_DBGIPC_TRANSPORT_DI) // CoreCLR activates debugger objects via direct COM rather than the shim (just like V1). For now we share the // same debug engine version as V2, though this may change in the future. diff --git a/src/runtime/src/coreclr/debug/di/rspriv.h b/src/runtime/src/coreclr/debug/di/rspriv.h index 53e732ee1c8..f85bd497e38 100644 --- a/src/runtime/src/coreclr/debug/di/rspriv.h +++ b/src/runtime/src/coreclr/debug/di/rspriv.h @@ -2222,7 +2222,6 @@ class Cordb : public CordbBase, public ICorDebug, public ICorDebugRemote // CorDebug //----------------------------------------------------------- - static COM_METHOD CreateObjectV1(REFIID id, void **object); #if defined(FEATURE_DBGIPC_TRANSPORT_DI) static COM_METHOD CreateObjectTelesto(REFIID id, void ** pObject); #endif // FEATURE_DBGIPC_TRANSPORT_DI diff --git a/src/runtime/src/coreclr/debug/runtimeinfo/datadescriptor.h b/src/runtime/src/coreclr/debug/runtimeinfo/datadescriptor.h index c51980d8cf4..6ccf9ca684d 100644 --- a/src/runtime/src/coreclr/debug/runtimeinfo/datadescriptor.h +++ b/src/runtime/src/coreclr/debug/runtimeinfo/datadescriptor.h @@ -677,13 +677,11 @@ CDAC_TYPE_FIELD(InlinedCallFrame, /*pointer*/, CallerReturnAddress, offsetof(Inl CDAC_TYPE_FIELD(InlinedCallFrame, /*pointer*/, CalleeSavedFP, offsetof(InlinedCallFrame, m_pCalleeSavedFP)) CDAC_TYPE_END(InlinedCallFrame) -#ifdef FEATURE_EH_FUNCLETS CDAC_TYPE_BEGIN(SoftwareExceptionFrame) CDAC_TYPE_SIZE(sizeof(SoftwareExceptionFrame)) CDAC_TYPE_FIELD(SoftwareExceptionFrame, /*T_CONTEXT*/, TargetContext, cdac_data::TargetContext) CDAC_TYPE_FIELD(SoftwareExceptionFrame, /*pointer*/, ReturnAddress, cdac_data::ReturnAddress) CDAC_TYPE_END(SoftwareExceptionFrame) -#endif // FEATURE_EH_FUNCLETS CDAC_TYPE_BEGIN(FramedMethodFrame) CDAC_TYPE_SIZE(sizeof(FramedMethodFrame)) diff --git a/src/runtime/src/coreclr/gc/gc.cpp b/src/runtime/src/coreclr/gc/gc.cpp index fdf865fe43b..dbda2a4fd57 100644 --- a/src/runtime/src/coreclr/gc/gc.cpp +++ b/src/runtime/src/coreclr/gc/gc.cpp @@ -427,6 +427,12 @@ float mb (size_t num) return (float)((float)num / 1000.0 / 1000.0); } +inline +size_t gib (size_t num) +{ + return (num / 1024 / 1024 / 1024); +} + #ifdef BACKGROUND_GC uint32_t bgc_alloc_spin_count = 140; uint32_t bgc_alloc_spin_count_uoh = 16; @@ -3908,6 +3914,10 @@ bool region_allocator::init (uint8_t* start, uint8_t* end, size_t alignment, uin *lowest = global_region_start; *highest = global_region_end; } + else + { + log_init_error_to_host ("global region allocator failed to allocate %zd bytes during init", (total_num_units * sizeof (uint32_t))); + } return (unit_map != 0); } @@ -9467,6 +9477,7 @@ bool gc_heap::inplace_commit_card_table (uint8_t* from, uint8_t* to) succeed = virtual_commit (commit_begins[i], commit_sizes[i], recorded_committed_bookkeeping_bucket); if (!succeed) { + log_init_error_to_host ("Committing %zd bytes (%.3f mb) for GC bookkeeping element#%d failed", commit_sizes[i], mb (commit_sizes[i]), i); failed_commit = i; break; } @@ -9520,7 +9531,10 @@ uint32_t* gc_heap::make_card_table (uint8_t* start, uint8_t* end) bookkeeping_start = mem; if (!mem) + { + log_init_error_to_host ("Reserving %zd bytes (%.3f mb) for GC bookkeeping failed", alloc_size, mb (alloc_size)); return 0; + } dprintf (2, ("Init - Card table alloc for %zd bytes: [%zx, %zx[", alloc_size, (size_t)mem, (size_t)(mem+alloc_size))); @@ -12398,6 +12412,7 @@ heap_segment* gc_heap::make_heap_segment (uint8_t* new_pages, size_t size, gc_he if (!virtual_commit (new_pages, initial_commit, oh, h_number)) { + log_init_error_to_host ("Committing %zd bytes for a region failed", initial_commit); return 0; } @@ -14345,6 +14360,7 @@ bool allocate_initial_regions(int number_of_heaps) initial_regions = new (nothrow) uint8_t*[number_of_heaps][total_generation_count][2]; if (initial_regions == nullptr) { + log_init_error_to_host ("allocate_initial_regions failed to allocate %zd bytes", (number_of_heaps * total_generation_count * 2 * sizeof (uint8_t*))); return false; } for (int i = 0; i < number_of_heaps; i++) @@ -14407,7 +14423,6 @@ HRESULT gc_heap::initialize_gc (size_t soh_segment_size, if (gc_config_log == NULL) { - GCToEEInterface::LogErrorToHost("Cannot create log file"); return E_FAIL; } @@ -14532,7 +14547,11 @@ HRESULT gc_heap::initialize_gc (size_t soh_segment_size, size_t reserve_size = regions_range; uint8_t* reserve_range = (uint8_t*)virtual_alloc (reserve_size, use_large_pages_p); if (!reserve_range) + { + log_init_error_to_host ("Reserving %zd bytes (%zd GiB) for the regions range failed, do you have a virtual memory limit set on this process?", + reserve_size, gib (reserve_size)); return E_OUTOFMEMORY; + } if (!global_region_allocator.init (reserve_range, (reserve_range + reserve_size), ((size_t)1 << min_segment_size_shr), @@ -14545,7 +14564,7 @@ HRESULT gc_heap::initialize_gc (size_t soh_segment_size, else { assert (!"cannot use regions without specifying the range!!!"); - GCToEEInterface::LogErrorToHost("Cannot use regions without specifying the range (using DOTNET_GCRegionRange)"); + log_init_error_to_host ("Regions range is 0! unexpected"); return E_FAIL; } #else //USE_REGIONS @@ -14685,7 +14704,7 @@ HRESULT gc_heap::initialize_gc (size_t soh_segment_size, if (!init_semi_shared()) { - GCToEEInterface::LogErrorToHost("PER_HEAP_ISOLATED data members initialization failed"); + log_init_error_to_host ("PER_HEAP_ISOLATED data members initialization failed"); hres = E_FAIL; } @@ -49226,6 +49245,7 @@ HRESULT GCHeap::Initialize() memset (gc_heap::committed_by_oh, 0, sizeof (gc_heap::committed_by_oh)); if (!gc_heap::compute_hard_limit()) { + log_init_error_to_host ("compute_hard_limit failed, check your heap hard limit related configs"); return CLR_E_GC_BAD_HARD_LIMIT; } @@ -49243,6 +49263,7 @@ HRESULT GCHeap::Initialize() uintptr_t config_affinity_mask = static_cast(GCConfig::GetGCHeapAffinitizeMask()); if (!ParseGCHeapAffinitizeRanges(cpu_index_ranges_holder.Get(), &config_affinity_set, config_affinity_mask)) { + log_init_error_to_host ("ParseGCHeapAffinitizeRange failed, check your HeapAffinitizeRanges config"); return CLR_E_GC_BAD_AFFINITY_CONFIG_FORMAT; } @@ -49251,6 +49272,7 @@ HRESULT GCHeap::Initialize() if (process_affinity_set->IsEmpty()) { + log_init_error_to_host ("This process is affinitize to 0 CPUs, check your GC heap affinity related configs"); return CLR_E_GC_BAD_AFFINITY_CONFIG; } @@ -49393,6 +49415,8 @@ HRESULT GCHeap::Initialize() if (gc_region_size >= MAX_REGION_SIZE) { + log_init_error_to_host ("The GC RegionSize config is set to %zd bytes (%zd GiB), it needs to be < %zd GiB", + gc_region_size, gib (gc_region_size), gib (MAX_REGION_SIZE)); return CLR_E_GC_BAD_REGION_SIZE; } @@ -49421,6 +49445,8 @@ HRESULT GCHeap::Initialize() if (!power_of_two_p(gc_region_size) || ((gc_region_size * nhp * min_regions_per_heap) > gc_heap::regions_range)) { + log_init_error_to_host ("Region size is %zd bytes, range is %zd bytes, (%d heaps * %d regions/heap = %d) regions needed initially", + gc_region_size, gc_heap::regions_range, nhp, min_regions_per_heap, (nhp * min_regions_per_heap)); return E_OUTOFMEMORY; } @@ -49495,7 +49521,7 @@ HRESULT GCHeap::Initialize() if (!WaitForGCEvent->CreateManualEventNoThrow(TRUE)) { - GCToEEInterface::LogErrorToHost("Creation of WaitForGCEvent failed"); + log_init_error_to_host ("Creation of WaitForGCEvent failed"); return E_FAIL; } @@ -49584,12 +49610,10 @@ HRESULT GCHeap::Initialize() uint8_t* numa_mem = (uint8_t*)GCToOSInterface::VirtualReserve (hb_info_size_per_node, 0, 0, (uint16_t)numa_node_index); if (!numa_mem) { - GCToEEInterface::LogErrorToHost("Reservation of numa_mem failed"); return E_FAIL; } if (!GCToOSInterface::VirtualCommit (numa_mem, hb_info_size_per_node, (uint16_t)numa_node_index)) { - GCToEEInterface::LogErrorToHost("Commit of numa_mem failed"); return E_FAIL; } @@ -49691,7 +49715,6 @@ HRESULT GCHeap::Initialize() if (seg_mem == nullptr) { - GCToEEInterface::LogErrorToHost("STRESS_REGIONS couldn't allocate ro segment"); hr = E_FAIL; break; } @@ -49705,7 +49728,6 @@ HRESULT GCHeap::Initialize() if (!RegisterFrozenSegment(&seg_info)) { - GCToEEInterface::LogErrorToHost("STRESS_REGIONS failed to RegisterFrozenSegment"); hr = E_FAIL; break; } diff --git a/src/runtime/src/coreclr/gc/gc.h b/src/runtime/src/coreclr/gc/gc.h index a1586ce8f68..4c2e3a04a7f 100644 --- a/src/runtime/src/coreclr/gc/gc.h +++ b/src/runtime/src/coreclr/gc/gc.h @@ -392,4 +392,6 @@ void GCLog (const char *fmt, ... ); FILE* CreateLogFile(const GCConfigStringHolder& temp_logfile_name, bool is_config); #endif //TRACE_GC || GC_CONFIG_DRIVEN +void log_init_error_to_host (const char* format, ...); + #endif // __GC_H diff --git a/src/runtime/src/coreclr/gc/gccommon.cpp b/src/runtime/src/coreclr/gc/gccommon.cpp index f68b06d818e..822d9c4349a 100644 --- a/src/runtime/src/coreclr/gc/gccommon.cpp +++ b/src/runtime/src/coreclr/gc/gccommon.cpp @@ -132,6 +132,12 @@ FILE* CreateLogFile(const GCConfigStringHolder& temp_logfile_name, bool is_confi //_snprintf_s(logfile_name, MAX_LONGPATH+1, _TRUNCATE, "%s.%d%s", temp_logfile_name.Get(), pid, suffix); _snprintf_s(logfile_name, MAX_LONGPATH+1, _TRUNCATE, "%s%s", temp_logfile_name.Get(), suffix); logFile = fopen(logfile_name, "wb"); + + if (logFile == NULL) + { + log_init_error_to_host ("Cannot create log file %s", logfile_name); + } + return logFile; } #endif //TRACE_GC || GC_CONFIG_DRIVEN @@ -159,7 +165,6 @@ HRESULT initialize_log_file() if (gc_log == NULL) { - GCToEEInterface::LogErrorToHost("Cannot create log file"); return E_FAIL; } @@ -168,7 +173,7 @@ HRESULT initialize_log_file() if (gc_log_file_size <= 0 || gc_log_file_size > 500) { - GCToEEInterface::LogErrorToHost("Invalid log file size (valid size needs to be larger than 0 and smaller than 500)"); + log_init_error_to_host ("Invalid log file size %zd MiB (valid size needs to be > 0 and <= 500 MiB)", gc_log_file_size); fclose (gc_log); return E_FAIL; } @@ -265,4 +270,15 @@ void GCLog (const char *fmt, ... ) } #endif //TRACE_GC && SIMPLE_DPRINTF +// We log initialization errors to the host to help with diagnostics. By default these will show up in stdout. +// You can also redirect them to a file. See docs/design/features/host-tracing.md. +void log_init_error_to_host (const char* format, ...) +{ + char error_buf[256]; + va_list args; + va_start (args, format); + _vsnprintf_s (error_buf, ARRAY_SIZE (error_buf), _TRUNCATE, format, args); + GCToEEInterface::LogErrorToHost (error_buf); + va_end (args); +} #endif // !DACCESS_COMPILE diff --git a/src/runtime/src/coreclr/gc/gcconfig.h b/src/runtime/src/coreclr/gc/gcconfig.h index 5b97c021bbd..0378323b6e9 100644 --- a/src/runtime/src/coreclr/gc/gcconfig.h +++ b/src/runtime/src/coreclr/gc/gcconfig.h @@ -104,8 +104,8 @@ class GCConfigStringHolder INT_CONFIG (GCHeapHardLimit, "GCHeapHardLimit", "System.GC.HeapHardLimit", 0, "Specifies a hard limit for the GC heap") \ INT_CONFIG (GCHeapHardLimitPercent, "GCHeapHardLimitPercent", "System.GC.HeapHardLimitPercent", 0, "Specifies the GC heap usage as a percentage of the total memory") \ INT_CONFIG (GCTotalPhysicalMemory, "GCTotalPhysicalMemory", NULL, 0, "Specifies what the GC should consider to be total physical memory") \ - INT_CONFIG (GCRegionRange, "GCRegionRange", NULL, 0, "Specifies the range for the GC heap") \ - INT_CONFIG (GCRegionSize, "GCRegionSize", NULL, 0, "Specifies the size for a basic GC region") \ + INT_CONFIG (GCRegionRange, "GCRegionRange", "System.GC.RegionRange", 0, "Specifies the range for the GC heap") \ + INT_CONFIG (GCRegionSize, "GCRegionSize", "System.GC.RegionSize", 0, "Specifies the size for a basic GC region") \ INT_CONFIG (GCEnableSpecialRegions, "GCEnableSpecialRegions", NULL, 0, "Specifies to enable special handling some regions like SIP") \ STRING_CONFIG(LogFile, "GCLogFile", NULL, "Specifies the name of the GC log file") \ STRING_CONFIG(ConfigLogFile, "GCConfigLogFile", NULL, "Specifies the name of the GC config log file") \ @@ -142,7 +142,7 @@ class GCConfigStringHolder INT_CONFIG (GCSpinCountUnit, "GCSpinCountUnit", NULL, 0, "Specifies the spin count unit used by the GC.") \ INT_CONFIG (GCDynamicAdaptationMode, "GCDynamicAdaptationMode", "System.GC.DynamicAdaptationMode", 1, "Enable the GC to dynamically adapt to application sizes.") \ INT_CONFIG (GCDTargetTCP, "GCDTargetTCP", "System.GC.DTargetTCP", 0, "Specifies the target tcp for DATAS") \ - INT_CONFIG (GCDBGCRatio, " GCDBGCRatio", NULL, 0, "Specifies the ratio of BGC to NGC2 for HC change") \ + INT_CONFIG (GCDBGCRatio, "GCDBGCRatio", NULL, 0, "Specifies the ratio of BGC to NGC2 for HC change") \ BOOL_CONFIG (GCCacheSizeFromSysConf, "GCCacheSizeFromSysConf", NULL, false, "Specifies using sysconf to retrieve the last level cache size for Unix.") // This class is responsible for retreiving configuration information diff --git a/src/runtime/src/coreclr/inc/eetwain.h b/src/runtime/src/coreclr/inc/eetwain.h index 0635fdf3c99..59fdb2922c9 100644 --- a/src/runtime/src/coreclr/inc/eetwain.h +++ b/src/runtime/src/coreclr/inc/eetwain.h @@ -307,6 +307,10 @@ virtual void LeaveCatch(GCInfoToken gcInfoToken, PCONTEXT pCtx)=0; #else // FEATURE_EH_FUNCLETS virtual DWORD_PTR CallFunclet(OBJECTREF throwable, void* pHandler, REGDISPLAY *pRD, ExInfo *pExInfo, bool isFilter) = 0; +virtual void ResumeAfterCatch(CONTEXT *pContext, size_t targetSSP, bool fIntercepted) = 0; +#if defined(HOST_AMD64) && defined(HOST_WINDOWS) +virtual void UpdateSSP(PREGDISPLAY pRD) = 0; +#endif // HOST_AMD64 && HOST_WINDOWS #endif // FEATURE_EH_FUNCLETS #ifdef FEATURE_REMAP_FUNCTION @@ -553,6 +557,11 @@ virtual void LeaveCatch(GCInfoToken gcInfoToken, PCONTEXT pCtx); #else // FEATURE_EH_FUNCLETS virtual DWORD_PTR CallFunclet(OBJECTREF throwable, void* pHandler, REGDISPLAY *pRD, ExInfo *pExInfo, bool isFilter); +virtual void ResumeAfterCatch(CONTEXT *pContext, size_t targetSSP, bool fIntercepted); + +#if defined(HOST_AMD64) && defined(HOST_WINDOWS) +virtual void UpdateSSP(PREGDISPLAY pRD); +#endif // HOST_AMD64 && HOST_WINDOWS #endif // FEATURE_EH_FUNCLETS #ifdef FEATURE_REMAP_FUNCTION @@ -762,6 +771,10 @@ virtual void LeaveCatch(GCInfoToken gcInfoToken, } #else // FEATURE_EH_FUNCLETS virtual DWORD_PTR CallFunclet(OBJECTREF throwable, void* pHandler, REGDISPLAY *pRD, ExInfo *pExInfo, bool isFilter); +virtual void ResumeAfterCatch(CONTEXT *pContext, size_t targetSSP, bool fIntercepted); +#if defined(HOST_AMD64) && defined(HOST_WINDOWS) +virtual void UpdateSSP(PREGDISPLAY pRD); +#endif // HOST_AMD64 && HOST_WINDOWS #endif // FEATURE_EH_FUNCLETS #ifdef FEATURE_REMAP_FUNCTION diff --git a/src/runtime/src/coreclr/inc/jithelpers.h b/src/runtime/src/coreclr/inc/jithelpers.h index 3ea5ed3f7af..35994841224 100644 --- a/src/runtime/src/coreclr/inc/jithelpers.h +++ b/src/runtime/src/coreclr/inc/jithelpers.h @@ -132,11 +132,11 @@ JITHELPER(CORINFO_HELP_ISINSTANCEOF_EXCEPTION, JIT_IsInstanceOfException, METHOD__NIL) - DYNAMICJITHELPER(CORINFO_HELP_BOX, JIT_Box, METHOD__NIL) - JITHELPER(CORINFO_HELP_BOX_NULLABLE, JIT_Box, METHOD__NIL) - DYNAMICJITHELPER(CORINFO_HELP_UNBOX, NULL, METHOD__CASTHELPERS__UNBOX) - DYNAMICJITHELPER(CORINFO_HELP_UNBOX_TYPETEST,NULL, METHOD__CASTHELPERS__UNBOX_TYPETEST) - DYNAMICJITHELPER(CORINFO_HELP_UNBOX_NULLABLE,NULL, METHOD__CASTHELPERS__UNBOX_NULLABLE) + DYNAMICJITHELPER(CORINFO_HELP_BOX, NULL, METHOD__CASTHELPERS__BOX) + DYNAMICJITHELPER(CORINFO_HELP_BOX_NULLABLE, NULL, METHOD__CASTHELPERS__BOX_NULLABLE) + DYNAMICJITHELPER(CORINFO_HELP_UNBOX, NULL, METHOD__CASTHELPERS__UNBOX) + DYNAMICJITHELPER(CORINFO_HELP_UNBOX_TYPETEST, NULL, METHOD__CASTHELPERS__UNBOX_TYPETEST) + DYNAMICJITHELPER(CORINFO_HELP_UNBOX_NULLABLE, NULL, METHOD__CASTHELPERS__UNBOX_NULLABLE) DYNAMICJITHELPER(CORINFO_HELP_GETREFANY, NULL, METHOD__TYPED_REFERENCE__GETREFANY) DYNAMICJITHELPER(CORINFO_HELP_ARRADDR_ST, NULL, METHOD__CASTHELPERS__STELEMREF) diff --git a/src/runtime/src/coreclr/inc/mdfileformat.h b/src/runtime/src/coreclr/inc/mdfileformat.h index b510ff23be9..594957a886c 100644 --- a/src/runtime/src/coreclr/inc/mdfileformat.h +++ b/src/runtime/src/coreclr/inc/mdfileformat.h @@ -36,13 +36,6 @@ #define FILE_VER_MAJOR 1 #define FILE_VER_MINOR 1 -// These are the last legitimate 0.x version macros. The file format has -// sinced move up to 1.x (see macros above). After CLR 1.0/NT 5 RTM's, these -// macros should no longer be required or ever seen. -#define FILE_VER_MAJOR_v0 0 - -#define FILE_VER_MINOR_v0 19 - #define MAXSTREAMNAME 32 diff --git a/src/runtime/src/coreclr/inc/metadata.h b/src/runtime/src/coreclr/inc/metadata.h index 3fbdabfd112..4fe9f5dd231 100644 --- a/src/runtime/src/coreclr/inc/metadata.h +++ b/src/runtime/src/coreclr/inc/metadata.h @@ -1035,7 +1035,6 @@ DECLARE_INTERFACE_(IMDInternalImport, IUnknown) mdToken *tkEnclosedToken) PURE; // [OUT] The enclosed type token #define MD_STREAM_VER_1X 0x10000 -#define MD_STREAM_VER_2_B1 0x10001 #define MD_STREAM_VER_2 0x20000 STDMETHOD_(DWORD, GetMetadataStreamVersion)() PURE; //returns DWORD with major version of // MD stream in senior word and minor version--in junior word @@ -1046,30 +1045,6 @@ DECLARE_INTERFACE_(IMDInternalImport, IUnknown) LPCUTF8 *pszNamespace, // [OUT] Namespace of Custom Attribute. LPCUTF8 *pszName) PURE; // [OUT] Name of Custom Attribute. - STDMETHOD(SetOptimizeAccessForSpeed)(// S_OK or error - BOOL fOptSpeed) PURE; - - STDMETHOD(SetVerifiedByTrustedSource)(// S_OK or error - BOOL fVerified) PURE; - - STDMETHOD(GetRvaOffsetData)( - DWORD *pFirstMethodRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in MethodDef table. - DWORD *pMethodDefRecordSize, // [OUT] Size of each record in MethodDef table. - DWORD *pMethodDefCount, // [OUT] Number of records in MethodDef table. - DWORD *pFirstFieldRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in FieldRVA table. - DWORD *pFieldRvaRecordSize, // [OUT] Size of each record in FieldRVA table. - DWORD *pFieldRvaCount // [OUT] Number of records in FieldRVA table. - ) PURE; - - //---------------------------------------------------------------------------------------- - // !!! READ THIS !!! - // - // New methods have to be added at the end. The order and signatures of the existing methods - // have to be preserved. We need to maintain a backward compatibility for this interface to - // allow ildasm to work on SingleCLR. - // - //---------------------------------------------------------------------------------------- - }; // IMDInternalImport diff --git a/src/runtime/src/coreclr/inc/utilcode.h b/src/runtime/src/coreclr/inc/utilcode.h index 0221afafe08..b94b6b45866 100644 --- a/src/runtime/src/coreclr/inc/utilcode.h +++ b/src/runtime/src/coreclr/inc/utilcode.h @@ -3220,13 +3220,6 @@ HRESULT validateTokenSig( DWORD dwFlags, // [IN] Method flags. IMDInternalImport* pImport); // [IN] Internal MD Import interface ptr -//***************************************************************************** -// Determine the version number of the runtime that was used to build the -// specified image. The pMetadata pointer passed in is the pointer to the -// metadata contained in the image. -//***************************************************************************** -HRESULT GetImageRuntimeVersionString(PVOID pMetaData, LPCSTR* pString); - //***************************************************************************** // The registry keys and values that contain the information regarding // the default registered unmanaged debugger. diff --git a/src/runtime/src/coreclr/interpreter/compiler.cpp b/src/runtime/src/coreclr/interpreter/compiler.cpp index 2212dba9936..272d6efb346 100644 --- a/src/runtime/src/coreclr/interpreter/compiler.cpp +++ b/src/runtime/src/coreclr/interpreter/compiler.cpp @@ -3263,6 +3263,12 @@ int InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) } break; + case CEE_THROW: + AddIns(INTOP_THROW); + m_pLastNewIns->SetSVar(m_pStackPointer[-1].var); + m_ip += 1; + break; + default: assert(0); break; diff --git a/src/runtime/src/coreclr/interpreter/compiler.h b/src/runtime/src/coreclr/interpreter/compiler.h index 8b603fa03f1..de1884b763f 100644 --- a/src/runtime/src/coreclr/interpreter/compiler.h +++ b/src/runtime/src/coreclr/interpreter/compiler.h @@ -272,7 +272,7 @@ class InterpCompiler CORINFO_METHOD_INFO* m_methodInfo; #ifdef DEBUG const char *m_methodName; - bool m_verbose; + bool m_verbose = false; #endif static int32_t InterpGetMovForType(InterpType interpType, bool signExtend); diff --git a/src/runtime/src/coreclr/interpreter/intops.def b/src/runtime/src/coreclr/interpreter/intops.def index 10fdb834c4b..efdb1c4d4fe 100644 --- a/src/runtime/src/coreclr/interpreter/intops.def +++ b/src/runtime/src/coreclr/interpreter/intops.def @@ -261,6 +261,9 @@ OPDEF(INTOP_CALL_HELPER_PP, "call.helper.pp", 5, 1, 0, InterpOpThreeInts) OPDEF(INTOP_ZEROBLK_IMM, "zeroblk.imm", 3, 0, 1, InterpOpInt) OPDEF(INTOP_LOCALLOC, "localloc", 3, 1, 1, InterpOpNoArgs) OPDEF(INTOP_BREAKPOINT, "breakpoint", 1, 0, 0, InterpOpNoArgs) + +OPDEF(INTOP_THROW, "throw", 4, 0, 1, InterpOpInt) + OPDEF(INTOP_FAILFAST, "failfast", 1, 0, 0, InterpOpNoArgs) OPDEF(INTOP_GC_COLLECT, "gc.collect", 1, 0, 0, InterpOpNoArgs) diff --git a/src/runtime/src/coreclr/jit/codegen.h b/src/runtime/src/coreclr/jit/codegen.h index fb33bd77738..25eb7a0c25f 100644 --- a/src/runtime/src/coreclr/jit/codegen.h +++ b/src/runtime/src/coreclr/jit/codegen.h @@ -1539,7 +1539,7 @@ class CodeGen final : public CodeGenInterface } }; - OperandDesc genOperandDesc(GenTree* op); + OperandDesc genOperandDesc(instruction ins, GenTree* op); void inst_TT(instruction ins, emitAttr size, GenTree* op1); void inst_RV_TT(instruction ins, emitAttr size, regNumber op1Reg, GenTree* op2); diff --git a/src/runtime/src/coreclr/jit/codegenxarch.cpp b/src/runtime/src/coreclr/jit/codegenxarch.cpp index c33e2bf2888..69390fe6c34 100644 --- a/src/runtime/src/coreclr/jit/codegenxarch.cpp +++ b/src/runtime/src/coreclr/jit/codegenxarch.cpp @@ -437,8 +437,7 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, simd_t } else { - CORINFO_FIELD_HANDLE hnd = emit->emitSimd8Const(val8); - emit->emitIns_R_C(ins_Load(targetType), attr, targetReg, hnd, 0); + emit->emitSimdConstCompressedLoad(val, attr, targetReg); } break; } @@ -465,10 +464,9 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, simd_t } else { - simd16_t val16 = {}; + simd_t val16 = {}; memcpy(&val16, &val12, sizeof(val12)); - CORINFO_FIELD_HANDLE hnd = emit->emitSimd16Const(val16); - emit->emitIns_R_C(ins_Load(targetType), attr, targetReg, hnd, 0); + emit->emitSimdConstCompressedLoad(val, EA_16BYTE, targetReg); } break; } @@ -495,8 +493,7 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, simd_t } else { - CORINFO_FIELD_HANDLE hnd = emit->emitSimd16Const(val16); - emit->emitIns_R_C(ins_Load(targetType), attr, targetReg, hnd, 0); + emit->emitSimdConstCompressedLoad(val, attr, targetReg); } break; } @@ -523,8 +520,7 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, simd_t } else { - CORINFO_FIELD_HANDLE hnd = emit->emitSimd32Const(val32); - emit->emitIns_R_C(ins_Load(targetType), attr, targetReg, hnd, 0); + emit->emitSimdConstCompressedLoad(val, attr, targetReg); } break; } @@ -549,8 +545,7 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, simd_t } else { - CORINFO_FIELD_HANDLE hnd = emit->emitSimd64Const(val64); - emit->emitIns_R_C(ins_Load(targetType), attr, targetReg, hnd, 0); + emit->emitSimdConstCompressedLoad(val, attr, targetReg); } break; } diff --git a/src/runtime/src/coreclr/jit/decomposelongs.cpp b/src/runtime/src/coreclr/jit/decomposelongs.cpp index 0461a12d181..ddc55e63329 100644 --- a/src/runtime/src/coreclr/jit/decomposelongs.cpp +++ b/src/runtime/src/coreclr/jit/decomposelongs.cpp @@ -137,7 +137,12 @@ GenTree* DecomposeLongs::DecomposeNode(GenTree* tree) } } +#if defined(FEATURE_HW_INTRINSICS) && defined(TARGET_X86) + if (!tree->TypeIs(TYP_LONG) && + !(tree->OperIs(GT_CAST) && varTypeIsLong(tree->AsCast()->CastOp()) && varTypeIsFloating(tree))) +#else if (!tree->TypeIs(TYP_LONG)) +#endif // FEATURE_HW_INTRINSICS && TARGET_X86 { return tree->gtNext; } @@ -157,15 +162,18 @@ GenTree* DecomposeLongs::DecomposeNode(GenTree* tree) GenTree* user = use.User(); - if (user->OperIsHWIntrinsic()) + if (tree->TypeIs(TYP_LONG) && (user->OperIsHWIntrinsic() || (user->OperIs(GT_CAST) && varTypeIsFloating(user)))) { if (tree->OperIs(GT_CNS_LNG) || (tree->OperIs(GT_IND, GT_LCL_FLD) && m_lowering->IsSafeToContainMem(user, tree))) { - NamedIntrinsic intrinsicId = user->AsHWIntrinsic()->GetHWIntrinsicId(); - assert(HWIntrinsicInfo::IsVectorCreate(intrinsicId) || - HWIntrinsicInfo::IsVectorCreateScalar(intrinsicId) || - HWIntrinsicInfo::IsVectorCreateScalarUnsafe(intrinsicId)); + if (user->OperIsHWIntrinsic()) + { + NamedIntrinsic intrinsicId = user->AsHWIntrinsic()->GetHWIntrinsicId(); + assert(HWIntrinsicInfo::IsVectorCreate(intrinsicId) || + HWIntrinsicInfo::IsVectorCreateScalar(intrinsicId) || + HWIntrinsicInfo::IsVectorCreateScalarUnsafe(intrinsicId)); + } return tree->gtNext; } @@ -562,28 +570,78 @@ GenTree* DecomposeLongs::DecomposeStoreLclFld(LIR::Use& use) GenTree* DecomposeLongs::DecomposeCast(LIR::Use& use) { assert(use.IsInitialized()); - assert(use.Def()->OperGet() == GT_CAST); + assert(use.Def()->OperIs(GT_CAST)); - GenTree* cast = use.Def()->AsCast(); - GenTree* loResult = nullptr; - GenTree* hiResult = nullptr; + GenTreeCast* cast = use.Def()->AsCast(); + var_types srcType = cast->CastFromType(); + var_types dstType = cast->CastToType(); - var_types srcType = cast->CastFromType(); - var_types dstType = cast->CastToType(); - - if ((cast->gtFlags & GTF_UNSIGNED) != 0) + if (cast->IsUnsigned()) { srcType = varTypeToUnsigned(srcType); } - bool skipDecomposition = false; +#if defined(FEATURE_HW_INTRINSICS) && defined(TARGET_X86) + if (varTypeIsFloating(dstType)) + { + // We will reach this path only if morph did not convert the cast to a helper call, + // meaning we can perform the cast using SIMD instructions. + // The sequence this creates is simply: + // AVX512DQ.VL.ConvertToVector128Single(Vector128.CreateScalarUnsafe(LONG)).ToScalar() + + NamedIntrinsic intrinsicId = NI_Illegal; + GenTree* srcOp = cast->CastOp(); + var_types dstType = cast->CastToType(); + CorInfoType baseFloatingType = (dstType == TYP_FLOAT) ? CORINFO_TYPE_FLOAT : CORINFO_TYPE_DOUBLE; + CorInfoType baseIntegralType = cast->IsUnsigned() ? CORINFO_TYPE_ULONG : CORINFO_TYPE_LONG; + + assert(!cast->gtOverflow()); + + if (m_compiler->compOpportunisticallyDependsOn(InstructionSet_AVX512DQ_VL)) + { + intrinsicId = (dstType == TYP_FLOAT) ? NI_AVX512DQ_VL_ConvertToVector128Single + : NI_AVX512DQ_VL_ConvertToVector128Double; + } + else + { + assert(m_compiler->compIsaSupportedDebugOnly(InstructionSet_AVX10v1)); + intrinsicId = + (dstType == TYP_FLOAT) ? NI_AVX10v1_ConvertToVector128Single : NI_AVX10v1_ConvertToVector128Double; + } + + GenTree* createScalar = m_compiler->gtNewSimdCreateScalarUnsafeNode(TYP_SIMD16, srcOp, baseIntegralType, 16); + GenTree* convert = + m_compiler->gtNewSimdHWIntrinsicNode(TYP_SIMD16, createScalar, intrinsicId, baseIntegralType, 16); + GenTree* toScalar = m_compiler->gtNewSimdToScalarNode(dstType, convert, baseFloatingType, 16); + + Range().InsertAfter(cast, createScalar, convert, toScalar); + Range().Remove(cast); + + if (createScalar->IsCnsVec()) + { + Range().Remove(srcOp); + } + + if (use.IsDummyUse()) + { + toScalar->SetUnusedValue(); + } + use.ReplaceWith(toScalar); + + return toScalar->gtNext; + } +#endif // FEATURE_HW_INTRINSICS && TARGET_X86 + + bool skipDecomposition = false; + GenTree* loResult = nullptr; + GenTree* hiResult = nullptr; if (varTypeIsLong(srcType)) { if (cast->gtOverflow() && (varTypeIsUnsigned(srcType) != varTypeIsUnsigned(dstType))) { - GenTree* srcOp = cast->gtGetOp1(); - noway_assert(srcOp->OperGet() == GT_LONG); + GenTree* srcOp = cast->CastOp(); + noway_assert(srcOp->OperIs(GT_LONG)); GenTree* loSrcOp = srcOp->gtGetOp1(); GenTree* hiSrcOp = srcOp->gtGetOp2(); @@ -595,13 +653,13 @@ GenTree* DecomposeLongs::DecomposeCast(LIR::Use& use) // check provided by codegen. // - const bool signExtend = (cast->gtFlags & GTF_UNSIGNED) == 0; + const bool signExtend = !cast->IsUnsigned(); loResult = EnsureIntSized(loSrcOp, signExtend); hiResult = cast; hiResult->gtType = TYP_INT; hiResult->AsCast()->gtCastType = TYP_UINT; - hiResult->gtFlags &= ~GTF_UNSIGNED; + hiResult->ClearUnsigned(); hiResult->AsOp()->gtOp1 = hiSrcOp; Range().Remove(srcOp); @@ -631,7 +689,7 @@ GenTree* DecomposeLongs::DecomposeCast(LIR::Use& use) } else { - if (!use.IsDummyUse() && (use.User()->OperGet() == GT_MUL)) + if (!use.IsDummyUse() && use.User()->OperIs(GT_MUL)) { // // This int->long cast is used by a GT_MUL that will be transformed by DecomposeMul into a @@ -646,7 +704,7 @@ GenTree* DecomposeLongs::DecomposeCast(LIR::Use& use) } else if (varTypeIsUnsigned(srcType)) { - const bool signExtend = (cast->gtFlags & GTF_UNSIGNED) == 0; + const bool signExtend = !cast->IsUnsigned(); loResult = EnsureIntSized(cast->gtGetOp1(), signExtend); hiResult = m_compiler->gtNewZeroConNode(TYP_INT); diff --git a/src/runtime/src/coreclr/jit/emit.cpp b/src/runtime/src/coreclr/jit/emit.cpp index 88d338c2d04..40264818097 100644 --- a/src/runtime/src/coreclr/jit/emit.cpp +++ b/src/runtime/src/coreclr/jit/emit.cpp @@ -8195,35 +8195,142 @@ CORINFO_FIELD_HANDLE emitter::emitSimd16Const(simd16_t constValue) return emitComp->eeFindJitDataOffs(cnum); } -#if defined(TARGET_XARCH) -CORINFO_FIELD_HANDLE emitter::emitSimd32Const(simd32_t constValue) +#ifdef TARGET_XARCH +//------------------------------------------------------------------------ +// emitSimdConst: Create a simd data section constant. +// +// Arguments: +// constValue - constant value +// attr - The EA_SIZE for the constant type +// +// Return Value: +// A field handle representing the data offset to access the constant. +// +// Note: +// Access to inline data is 'abstracted' by a special type of static member +// (produced by eeFindJitDataOffs) which the emitter recognizes as being a reference +// to constant data, not a real static field. +// +CORINFO_FIELD_HANDLE emitter::emitSimdConst(simd_t* constValue, emitAttr attr) { - unsigned cnsSize = 32; - unsigned cnsAlign = cnsSize; + unsigned cnsSize = EA_SIZE(attr); + unsigned cnsAlign = cnsSize; + var_types dataType = (cnsSize >= 8) ? emitComp->getSIMDTypeForSize(cnsSize) : TYP_FLOAT; +#ifdef TARGET_XARCH if (emitComp->compCodeOpt() == Compiler::SMALL_CODE) { cnsAlign = dataSection::MIN_DATA_ALIGN; } +#endif // TARGET_XARCH - UNATIVE_OFFSET cnum = emitDataConst(&constValue, cnsSize, cnsAlign, TYP_SIMD32); + UNATIVE_OFFSET cnum = emitDataConst(constValue, cnsSize, cnsAlign, dataType); return emitComp->eeFindJitDataOffs(cnum); } -CORINFO_FIELD_HANDLE emitter::emitSimd64Const(simd64_t constValue) +//------------------------------------------------------------------------ +// emitSimdConstCompressedLoad: Create a simd data section constant, +// compressing it if possible, and emit an appropiate instruction +// to load or broadcast the constant to a register. +// +// Arguments: +// constValue - constant value +// attr - The EA_SIZE for the constant type +// targetReg - The target register +// +void emitter::emitSimdConstCompressedLoad(simd_t* constValue, emitAttr attr, regNumber targetReg) { - unsigned cnsSize = 64; - unsigned cnsAlign = cnsSize; + assert(EA_SIZE(attr) >= 8 && EA_SIZE(attr) <= 64); - if (emitComp->compCodeOpt() == Compiler::SMALL_CODE) + unsigned cnsSize = EA_SIZE(attr); + unsigned dataSize = cnsSize; + instruction ins = (cnsSize == 8) ? INS_movsd_simd : INS_movups; + + // Most constant vectors tend to have repeated values, so we will first check to see if + // we can replace a full vector load with a smaller broadcast. + + if ((dataSize == 64) && (constValue->v256[1] == constValue->v256[0])) { - cnsAlign = dataSection::MIN_DATA_ALIGN; + assert(emitComp->IsBaselineVector512IsaSupportedDebugOnly()); + dataSize = 32; + ins = INS_vbroadcastf32x8; } - UNATIVE_OFFSET cnum = emitDataConst(&constValue, cnsSize, cnsAlign, TYP_SIMD64); - return emitComp->eeFindJitDataOffs(cnum); -} + if ((dataSize == 32) && (constValue->v128[1] == constValue->v128[0])) + { + assert(emitComp->IsBaselineVector256IsaSupportedDebugOnly()); + dataSize = 16; + ins = INS_vbroadcastf128; + } + if ((dataSize == 16) && (constValue->u64[1] == constValue->u64[0])) + { + if (((cnsSize == 16) && emitComp->compOpportunisticallyDependsOn(InstructionSet_SSE3)) || + emitComp->compOpportunisticallyDependsOn(InstructionSet_AVX)) + { + dataSize = 8; + ins = (cnsSize == 16) ? INS_movddup : INS_vbroadcastsd; + } + } + + // `vbroadcastss` fills the full SIMD register, so we can't do this last step if the + // original constant was smaller than a full reg (e.g. TYP_SIMD8) + + if ((dataSize == 8) && (cnsSize >= 16) && (constValue->u32[1] == constValue->u32[0])) + { + if (emitComp->compOpportunisticallyDependsOn(InstructionSet_AVX)) + { + dataSize = 4; + ins = INS_vbroadcastss; + } + } + + if (dataSize < cnsSize) + { + // We found a broadcast match, so emit the broadcast instruction and return. + // Here we use the original emitAttr for the instruction, because we need to + // produce a register of the original constant's size, filled with the pattern. + + CORINFO_FIELD_HANDLE hnd = emitSimdConst(constValue, EA_ATTR(dataSize)); + emitIns_R_C(ins, attr, targetReg, hnd, 0); + return; + } + + // Otherwise, if the upper lanes and/or elements of the constant are zero, we can use a + // smaller load, because all scalar and vector memory load instructions zero the uppers. + + simd32_t zeroValue = {}; + + if ((dataSize == 64) && (constValue->v256[1] == zeroValue)) + { + dataSize = 32; + } + + if ((dataSize == 32) && (constValue->v128[1] == zeroValue.v128[0])) + { + dataSize = 16; + } + + if ((dataSize == 16) && (constValue->u64[1] == 0)) + { + dataSize = 8; + ins = INS_movsd_simd; + } + + if ((dataSize == 8) && (constValue->u32[1] == 0)) + { + dataSize = 4; + ins = INS_movss; + } + + // Here we set the emitAttr to the size of the actual load. It will zero extend + // up to the native SIMD register size. + + attr = EA_ATTR(dataSize); + + CORINFO_FIELD_HANDLE hnd = emitSimdConst(constValue, attr); + emitIns_R_C(ins, attr, targetReg, hnd, 0); +} #endif // TARGET_XARCH #if defined(FEATURE_MASKED_HW_INTRINSICS) diff --git a/src/runtime/src/coreclr/jit/emit.h b/src/runtime/src/coreclr/jit/emit.h index 2d971ee158f..f9c37456e24 100644 --- a/src/runtime/src/coreclr/jit/emit.h +++ b/src/runtime/src/coreclr/jit/emit.h @@ -2658,10 +2658,9 @@ class emitter CORINFO_FIELD_HANDLE emitSimd8Const(simd8_t constValue); CORINFO_FIELD_HANDLE emitSimd16Const(simd16_t constValue); #if defined(TARGET_XARCH) - CORINFO_FIELD_HANDLE emitSimd32Const(simd32_t constValue); - CORINFO_FIELD_HANDLE emitSimd64Const(simd64_t constValue); + CORINFO_FIELD_HANDLE emitSimdConst(simd_t* constValue, emitAttr attr); + void emitSimdConstCompressedLoad(simd_t* constValue, emitAttr attr, regNumber targetReg); #endif // TARGET_XARCH - #if defined(FEATURE_MASKED_HW_INTRINSICS) CORINFO_FIELD_HANDLE emitSimdMaskConst(simdmask_t constValue); #endif // FEATURE_MASKED_HW_INTRINSICS diff --git a/src/runtime/src/coreclr/jit/emitxarch.cpp b/src/runtime/src/coreclr/jit/emitxarch.cpp index 079e2626543..85794160e95 100644 --- a/src/runtime/src/coreclr/jit/emitxarch.cpp +++ b/src/runtime/src/coreclr/jit/emitxarch.cpp @@ -7331,6 +7331,7 @@ bool emitter::IsMovInstruction(instruction ins) case INS_vmovdqu8: case INS_vmovdqu16: case INS_vmovdqu64: + case INS_movq: case INS_movsd_simd: case INS_movss: case INS_movsx: @@ -7350,7 +7351,6 @@ bool emitter::IsMovInstruction(instruction ins) } #if defined(TARGET_AMD64) - case INS_movq: case INS_movsxd: { return true; @@ -7501,7 +7501,6 @@ bool emitter::HasSideEffect(instruction ins, emitAttr size) break; } -#if defined(TARGET_AMD64) case INS_movq: { // Clears the upper bits @@ -7509,6 +7508,7 @@ bool emitter::HasSideEffect(instruction ins, emitAttr size) break; } +#if defined(TARGET_AMD64) case INS_movsxd: { // Sign-extends the source @@ -7781,13 +7781,13 @@ void emitter::emitIns_Mov(instruction ins, emitAttr attr, regNumber dstReg, regN break; } -#if defined(TARGET_AMD64) case INS_movq: { assert(isFloatReg(dstReg) && isFloatReg(srcReg)); break; } +#if defined(TARGET_AMD64) case INS_movsxd: { assert(isGeneralRegister(dstReg) && isGeneralRegister(srcReg)); diff --git a/src/runtime/src/coreclr/jit/gentree.cpp b/src/runtime/src/coreclr/jit/gentree.cpp index 8754c2b24df..54af242fa6c 100644 --- a/src/runtime/src/coreclr/jit/gentree.cpp +++ b/src/runtime/src/coreclr/jit/gentree.cpp @@ -13038,14 +13038,18 @@ void Compiler::gtDispTree(GenTree* tree, #if defined(FEATURE_HW_INTRINSICS) case GT_HWINTRINSIC: - if (tree->OperIs(GT_HWINTRINSIC)) + { + GenTreeHWIntrinsic* node = tree->AsHWIntrinsic(); + printf(" %u", node->GetSimdSize()); + if (node->GetSimdBaseType() != TYP_UNKNOWN) + { + printf(" %s", varTypeName(node->GetSimdBaseType())); + } + if (node->GetAuxiliaryType() != TYP_UNKNOWN) { - printf(" %s %s", - tree->AsHWIntrinsic()->GetSimdBaseType() == TYP_UNKNOWN - ? "" - : varTypeName(tree->AsHWIntrinsic()->GetSimdBaseType()), - HWIntrinsicInfo::lookupName(tree->AsHWIntrinsic()->GetHWIntrinsicId())); + printf(" (aux %s)", varTypeName(node->GetAuxiliaryType())); } + printf(" %s", HWIntrinsicInfo::lookupName(node->GetHWIntrinsicId())); gtDispCommonEndLine(tree); @@ -13058,7 +13062,8 @@ void Compiler::gtDispTree(GenTree* tree, gtDispChild(operand, indentStack, ++index < count ? IIArc : IIArcBottom, nullptr, topOnly); } } - break; + } + break; #endif // defined(FEATURE_HW_INTRINSICS) case GT_ARR_ELEM: @@ -28323,9 +28328,6 @@ bool GenTreeHWIntrinsic::OperIsMemoryLoad(GenTree** pAddr) const case NI_AVX2_ConvertToVector256Int16: case NI_AVX2_ConvertToVector256Int32: case NI_AVX2_ConvertToVector256Int64: - case NI_AVX2_BroadcastVector128ToVector256: - case NI_AVX512F_BroadcastVector128ToVector512: - case NI_AVX512F_BroadcastVector256ToVector512: if (GetAuxiliaryJitType() == CORINFO_TYPE_PTR) { addr = Op(1); diff --git a/src/runtime/src/coreclr/jit/hwintrinsic.cpp b/src/runtime/src/coreclr/jit/hwintrinsic.cpp index a00d57962d7..f7eddafc80f 100644 --- a/src/runtime/src/coreclr/jit/hwintrinsic.cpp +++ b/src/runtime/src/coreclr/jit/hwintrinsic.cpp @@ -2078,9 +2078,6 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, case NI_AVX2_ConvertToVector256Int16: case NI_AVX2_ConvertToVector256Int32: case NI_AVX2_ConvertToVector256Int64: - case NI_AVX2_BroadcastVector128ToVector256: - case NI_AVX512F_BroadcastVector128ToVector512: - case NI_AVX512F_BroadcastVector256ToVector512: { // These intrinsics have both pointer and vector overloads // We want to be able to differentiate between them so lets diff --git a/src/runtime/src/coreclr/jit/hwintrinsiccodegenxarch.cpp b/src/runtime/src/coreclr/jit/hwintrinsiccodegenxarch.cpp index 19792a61c40..ea114113412 100644 --- a/src/runtime/src/coreclr/jit/hwintrinsiccodegenxarch.cpp +++ b/src/runtime/src/coreclr/jit/hwintrinsiccodegenxarch.cpp @@ -1076,7 +1076,7 @@ void CodeGen::genHWIntrinsic_R_RM( instOptions = AddEmbBroadcastMode(instOptions); } - OperandDesc rmOpDesc = genOperandDesc(rmOp); + OperandDesc rmOpDesc = genOperandDesc(ins, rmOp); if (((instOptions & INS_OPTS_EVEX_b_MASK) != 0) && (rmOpDesc.GetKind() == OperandKind::Reg)) { @@ -1361,7 +1361,7 @@ void CodeGen::genHWIntrinsic_R_R_RM_R(GenTreeHWIntrinsic* node, instruction ins, instOptions = AddEmbBroadcastMode(instOptions); } - OperandDesc op2Desc = genOperandDesc(op2); + OperandDesc op2Desc = genOperandDesc(ins, op2); if (op2Desc.IsContained()) { @@ -1431,7 +1431,7 @@ void CodeGen::genHWIntrinsic_R_R_R_RM(instruction ins, instOptions = AddEmbBroadcastMode(instOptions); } - OperandDesc op3Desc = genOperandDesc(op3); + OperandDesc op3Desc = genOperandDesc(ins, op3); if (((instOptions & INS_OPTS_EVEX_b_MASK) != 0) && (op3Desc.GetKind() == OperandKind::Reg)) { @@ -1547,7 +1547,7 @@ void CodeGen::genHWIntrinsic_R_R_R_RM_I( instOptions = AddEmbBroadcastMode(instOptions); } - OperandDesc op3Desc = genOperandDesc(op3); + OperandDesc op3Desc = genOperandDesc(ins, op3); switch (op3Desc.GetKind()) { @@ -1898,11 +1898,15 @@ void CodeGen::genBaseIntrinsic(GenTreeHWIntrinsic* node, insOpts instOptions) op1 = loPart; } - ins = INS_movq; baseAttr = EA_8BYTE; } #endif // TARGET_X86 + if (op1->isUsedFromMemory() && (baseAttr == EA_8BYTE)) + { + ins = INS_movq; + } + genHWIntrinsic_R_RM(node, ins, baseAttr, targetReg, op1, instOptions); } else @@ -1952,7 +1956,7 @@ void CodeGen::genBaseIntrinsic(GenTreeHWIntrinsic* node, insOpts instOptions) else { // `movq xmm xmm` zeroes the upper 64 bits. - genHWIntrinsic_R_RM(node, INS_movq, attr, targetReg, op1, instOptions); + emit->emitIns_Mov(INS_movq, attr, targetReg, op1Reg, /* canSkip */ false); } break; } @@ -2281,10 +2285,8 @@ void CodeGen::genBaseIntrinsic(GenTreeHWIntrinsic* node, insOpts instOptions) { minValueInt.i32[i] = INT_MIN; } - CORINFO_FIELD_HANDLE minValueFld = typeSize == EA_16BYTE ? emit->emitSimd16Const(minValueInt.v128[0]) - : emit->emitSimd32Const(minValueInt.v256[0]); - CORINFO_FIELD_HANDLE negOneFld = typeSize == EA_16BYTE ? emit->emitSimd16Const(negOneIntVec.v128[0]) - : emit->emitSimd32Const(negOneIntVec.v256[0]); + CORINFO_FIELD_HANDLE minValueFld = emit->emitSimdConst(&minValueInt, typeSize); + CORINFO_FIELD_HANDLE negOneFld = emit->emitSimdConst(&negOneIntVec, typeSize); // div-by-zero check emit->emitIns_SIMD_R_R_R(INS_xorpd, typeSize, tmpReg1, tmpReg1, tmpReg1, instOptions); diff --git a/src/runtime/src/coreclr/jit/hwintrinsiclistxarch.h b/src/runtime/src/coreclr/jit/hwintrinsiclistxarch.h index a49d4b4bdc6..d34af9561b3 100644 --- a/src/runtime/src/coreclr/jit/hwintrinsiclistxarch.h +++ b/src/runtime/src/coreclr/jit/hwintrinsiclistxarch.h @@ -843,7 +843,7 @@ HARDWARE_INTRINSIC(AVX2, Blend, HARDWARE_INTRINSIC(AVX2, BlendVariable, 32, 3, {INS_vpblendvb, INS_vpblendvb, INS_vpblendvb, INS_vpblendvb, INS_vpblendvb, INS_vpblendvb, INS_vpblendvb, INS_vpblendvb, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoEvexSemantics) HARDWARE_INTRINSIC(AVX2, BroadcastScalarToVector128, 16, 1, {INS_vpbroadcastb, INS_vpbroadcastb, INS_vpbroadcastw, INS_vpbroadcastw, INS_vpbroadcastd, INS_vpbroadcastd, INS_vpbroadcastq, INS_vpbroadcastq, INS_vbroadcastss, INS_movddup}, HW_Category_SIMDScalar, HW_Flag_MaybeMemoryLoad) HARDWARE_INTRINSIC(AVX2, BroadcastScalarToVector256, 32, 1, {INS_vpbroadcastb, INS_vpbroadcastb, INS_vpbroadcastw, INS_vpbroadcastw, INS_vpbroadcastd, INS_vpbroadcastd, INS_vpbroadcastq, INS_vpbroadcastq, INS_vbroadcastss, INS_vbroadcastsd}, HW_Category_SIMDScalar, HW_Flag_MaybeMemoryLoad) -HARDWARE_INTRINSIC(AVX2, BroadcastVector128ToVector256, 32, 1, {INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_MaybeMemoryLoad) +HARDWARE_INTRINSIC(AVX2, BroadcastVector128ToVector256, 32, 1, {INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AVX2, CompareEqual, 32, 2, {INS_pcmpeqb, INS_pcmpeqb, INS_pcmpeqw, INS_pcmpeqw, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqq, INS_pcmpeqq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative|HW_Flag_ReturnsPerElementMask|HW_Flag_NoEvexSemantics) HARDWARE_INTRINSIC(AVX2, CompareGreaterThan, 32, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_pcmpgtq, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_ReturnsPerElementMask|HW_Flag_NoEvexSemantics) HARDWARE_INTRINSIC(AVX2, CompareLessThan, 32, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_pcmpgtq, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_ReturnsPerElementMask|HW_Flag_NoEvexSemantics) @@ -915,8 +915,8 @@ HARDWARE_INTRINSIC(AVX512F, And, HARDWARE_INTRINSIC(AVX512F, AndNot, 64, 2, {INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_vpandnq, INS_vpandnq, INS_andnps, INS_andnpd}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_NormalizeSmallTypeToInt) HARDWARE_INTRINSIC(AVX512F, BlendVariable, 64, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(AVX512F, BroadcastScalarToVector512, 64, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpbroadcastd, INS_vpbroadcastd, INS_vpbroadcastq, INS_vpbroadcastq, INS_vbroadcastss, INS_vbroadcastsd}, HW_Category_SIMDScalar, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX512F, BroadcastVector128ToVector512, 64, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vbroadcasti128, INS_vbroadcasti128, INS_invalid, INS_invalid, INS_vbroadcastf128, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_MaybeMemoryLoad) -HARDWARE_INTRINSIC(AVX512F, BroadcastVector256ToVector512, 64, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vbroadcasti64x4, INS_vbroadcasti64x4, INS_invalid, INS_vbroadcastf64x4}, HW_Category_SimpleSIMD, HW_Flag_MaybeMemoryLoad) +HARDWARE_INTRINSIC(AVX512F, BroadcastVector128ToVector512, 64, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vbroadcasti128, INS_vbroadcasti128, INS_invalid, INS_invalid, INS_vbroadcastf128, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX512F, BroadcastVector256ToVector512, 64, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vbroadcasti64x4, INS_vbroadcasti64x4, INS_invalid, INS_vbroadcastf64x4}, HW_Category_MemoryLoad, HW_Flag_NoFlag) HARDWARE_INTRINSIC(AVX512F, Compare, 64, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(AVX512F, CompareEqual, 64, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(AVX512F, CompareGreaterThan, 64, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_InvalidNodeId) @@ -1466,9 +1466,11 @@ HARDWARE_INTRINSIC(AVX10v2, ConvertToVectorUInt64WithTruncationSaturatio HARDWARE_INTRINSIC(AVX10v2, Divide, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_divps, INS_divpd}, HW_Category_SimpleSIMD, HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible) HARDWARE_INTRINSIC(AVX10v2, MinMax, -1, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vminmaxps, INS_vminmaxpd}, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible) HARDWARE_INTRINSIC(AVX10v2, MinMaxScalar, -1, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vminmaxss, INS_vminmaxsd}, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg|HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible) +HARDWARE_INTRINSIC(AVX10v2, MoveScalar, 16, -1, {INS_invalid, INS_invalid, INS_vmovw, INS_vmovw, INS_vmovd, INS_vmovd, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoContainment) HARDWARE_INTRINSIC(AVX10v2, Multiply, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mulps, INS_mulpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative |HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible) HARDWARE_INTRINSIC(AVX10v2, Scale, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vscalefps, INS_vscalefpd}, HW_Category_SimpleSIMD, HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible) HARDWARE_INTRINSIC(AVX10v2, Sqrt, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtps, INS_sqrtpd}, HW_Category_SimpleSIMD, HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible) +HARDWARE_INTRINSIC(AVX10v2, StoreScalar, 16, 2, {INS_invalid, INS_invalid, INS_vmovw, INS_vmovw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) HARDWARE_INTRINSIC(AVX10v2, Subtract, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_subps, INS_subpd}, HW_Category_SimpleSIMD, HW_Flag_EmbBroadcastCompatible|HW_Flag_EmbMaskingCompatible|HW_Flag_EmbRoundingCompatible) #define LAST_NI_AVX10v2 NI_AVX10v2_Subtract diff --git a/src/runtime/src/coreclr/jit/instr.cpp b/src/runtime/src/coreclr/jit/instr.cpp index a0dbcaab36f..8610effb416 100644 --- a/src/runtime/src/coreclr/jit/instr.cpp +++ b/src/runtime/src/coreclr/jit/instr.cpp @@ -809,6 +809,7 @@ void CodeGen::inst_RV_SH( // logic for determining what "kind" of operand "op" is. // // Arguments: +// ins - The instruction that will consume the operand. // op - The operand node for which to obtain the descriptor. // // Return Value: @@ -818,7 +819,7 @@ void CodeGen::inst_RV_SH( // This method is not idempotent - it can only be called once for a // given node. // -CodeGen::OperandDesc CodeGen::genOperandDesc(GenTree* op) +CodeGen::OperandDesc CodeGen::genOperandDesc(instruction ins, GenTree* op) { if (!op->isContained() && !op->isUsedFromSpillTemp()) { @@ -915,7 +916,7 @@ CodeGen::OperandDesc CodeGen::genOperandDesc(GenTree* op) { // If the operand of broadcast is not a constant integer, // we handle all the other cases recursively. - return genOperandDesc(hwintrinsicChild); + return genOperandDesc(ins, hwintrinsicChild); } break; } @@ -935,7 +936,7 @@ CodeGen::OperandDesc CodeGen::genOperandDesc(GenTree* op) assert(hwintrinsic->isContained()); op = hwintrinsic->Op(1); - return genOperandDesc(op); + return genOperandDesc(ins, op); } default: @@ -989,59 +990,26 @@ CodeGen::OperandDesc CodeGen::genOperandDesc(GenTree* op) #if defined(FEATURE_SIMD) case GT_CNS_VEC: { - switch (op->TypeGet()) - { - case TYP_SIMD8: - { - simd8_t constValue; - memcpy(&constValue, &op->AsVecCon()->gtSimdVal, sizeof(simd8_t)); - return OperandDesc(emit->emitSimd8Const(constValue)); - } + insTupleType tupleType = emit->insTupleTypeInfo(ins); + unsigned cnsSize = genTypeSize(op); - case TYP_SIMD12: - { - simd16_t constValue = {}; - memcpy(&constValue, &op->AsVecCon()->gtSimdVal, sizeof(simd12_t)); - return OperandDesc(emit->emitSimd16Const(constValue)); - } - case TYP_SIMD16: - { - simd16_t constValue; - memcpy(&constValue, &op->AsVecCon()->gtSimdVal, sizeof(simd16_t)); - return OperandDesc(emit->emitSimd16Const(constValue)); - } - -#if defined(TARGET_XARCH) - case TYP_SIMD32: - { - simd32_t constValue; - memcpy(&constValue, &op->AsVecCon()->gtSimdVal, sizeof(simd32_t)); - return OperandDesc(emit->emitSimd32Const(constValue)); - } - - case TYP_SIMD64: - { - simd64_t constValue; - memcpy(&constValue, &op->AsVecCon()->gtSimdVal, sizeof(simd64_t)); - return OperandDesc(emit->emitSimd64Const(constValue)); - } - -#endif // TARGET_XARCH + if ((tupleType == INS_TT_TUPLE1_SCALAR) || (tupleType == INS_TT_TUPLE1_FIXED)) + { + // We have a vector const, but the instruction will only read a scalar from it, + // so don't waste space putting the entire vector to the data section. - default: - { - unreached(); - } + cnsSize = max(CodeGenInterface::instInputSize(ins), 4U); + assert(cnsSize <= genTypeSize(op)); } + + return OperandDesc(emit->emitSimdConst(&op->AsVecCon()->gtSimdVal, EA_TYPE(cnsSize))); } #endif // FEATURE_SIMD #if defined(FEATURE_MASKED_HW_INTRINSICS) case GT_CNS_MSK: { - simdmask_t constValue; - memcpy(&constValue, &op->AsMskCon()->gtSimdMaskVal, sizeof(simdmask_t)); - return OperandDesc(emit->emitSimdMaskConst(constValue)); + return OperandDesc(emit->emitSimdMaskConst(op->AsMskCon()->gtSimdMaskVal)); } #endif // FEATURE_MASKED_HW_INTRINSICS @@ -1071,7 +1039,7 @@ CodeGen::OperandDesc CodeGen::genOperandDesc(GenTree* op) void CodeGen::inst_TT(instruction ins, emitAttr size, GenTree* op1) { emitter* emit = GetEmitter(); - OperandDesc op1Desc = genOperandDesc(op1); + OperandDesc op1Desc = genOperandDesc(ins, op1); switch (op1Desc.GetKind()) { @@ -1120,7 +1088,7 @@ void CodeGen::inst_TT(instruction ins, emitAttr size, GenTree* op1) void CodeGen::inst_RV_TT(instruction ins, emitAttr size, regNumber op1Reg, GenTree* op2) { emitter* emit = GetEmitter(); - OperandDesc op2Desc = genOperandDesc(op2); + OperandDesc op2Desc = genOperandDesc(ins, op2); switch (op2Desc.GetKind()) { @@ -1202,7 +1170,7 @@ void CodeGen::inst_RV_TT_IV( } #endif // TARGET_XARCH && FEATURE_HW_INTRINSICS - OperandDesc rmOpDesc = genOperandDesc(rmOp); + OperandDesc rmOpDesc = genOperandDesc(ins, rmOp); switch (rmOpDesc.GetKind()) { @@ -1339,7 +1307,7 @@ void CodeGen::inst_RV_RV_TT(instruction ins, } #endif // TARGET_XARCH && FEATURE_HW_INTRINSICS - OperandDesc op2Desc = genOperandDesc(op2); + OperandDesc op2Desc = genOperandDesc(ins, op2); switch (op2Desc.GetKind()) { @@ -1426,7 +1394,7 @@ void CodeGen::inst_RV_RV_TT_IV(instruction ins, } #endif // TARGET_XARCH && FEATURE_HW_INTRINSICS - OperandDesc op2Desc = genOperandDesc(op2); + OperandDesc op2Desc = genOperandDesc(ins, op2); switch (op2Desc.GetKind()) { diff --git a/src/runtime/src/coreclr/jit/lower.cpp b/src/runtime/src/coreclr/jit/lower.cpp index 61de442555b..cc3cf97d919 100644 --- a/src/runtime/src/coreclr/jit/lower.cpp +++ b/src/runtime/src/coreclr/jit/lower.cpp @@ -550,13 +550,9 @@ GenTree* Lowering::LowerNode(GenTree* node) return nextNode; } - nextNode = LowerCast(node); - if (nextNode != nullptr) - { - return nextNode; - } + LowerCast(node); + break; } - break; case GT_BITCAST: { @@ -9694,7 +9690,7 @@ bool Lowering::GetLoadStoreCoalescingData(GenTreeIndir* ind, LoadStoreCoalescing // void Lowering::LowerStoreIndirCoalescing(GenTreeIndir* ind) { -// LA, RISC-V and ARM32 more likely to recieve a terrible performance hit from +// LA, RISC-V and ARM32 more likely to receive a terrible performance hit from // unaligned accesses making this optimization questionable. #if defined(TARGET_XARCH) || defined(TARGET_ARM64) if (!comp->opts.OptimizationEnabled()) @@ -10162,7 +10158,7 @@ GenTree* Lowering::LowerIndir(GenTreeIndir* ind) #endif // TODO-Cleanup: We're passing isContainable = true but ContainCheckIndir rejects - // address containment in some cases so we end up creating trivial (reg + offfset) + // address containment in some cases so we end up creating trivial (reg + offset) // or (reg + reg) LEAs that are not necessary. #if defined(TARGET_ARM64) diff --git a/src/runtime/src/coreclr/jit/lower.h b/src/runtime/src/coreclr/jit/lower.h index fb8c06ba6f6..e8ddda4c822 100644 --- a/src/runtime/src/coreclr/jit/lower.h +++ b/src/runtime/src/coreclr/jit/lower.h @@ -136,7 +136,6 @@ class Lowering final : public Phase void ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node); #ifdef TARGET_XARCH void TryFoldCnsVecForEmbeddedBroadcast(GenTreeHWIntrinsic* parentNode, GenTreeVecCon* childNode); - void TryCompressConstVecData(GenTreeStoreInd* node); #endif // TARGET_XARCH #endif // FEATURE_HW_INTRINSICS @@ -428,7 +427,7 @@ class Lowering final : public Phase GenTree* switchValue, weight_t defaultLikelihood); - GenTree* LowerCast(GenTree* node); + void LowerCast(GenTree* node); #if !CPU_LOAD_STORE_ARCH bool IsRMWIndirCandidate(GenTree* operand, GenTree* storeInd); diff --git a/src/runtime/src/coreclr/jit/lowerarmarch.cpp b/src/runtime/src/coreclr/jit/lowerarmarch.cpp index 47fbb10db49..e6b5c34181f 100644 --- a/src/runtime/src/coreclr/jit/lowerarmarch.cpp +++ b/src/runtime/src/coreclr/jit/lowerarmarch.cpp @@ -968,22 +968,11 @@ void Lowering::LowerPutArgStkOrSplit(GenTreePutArgStk* putArgNode) // tree - GT_CAST node to be lowered // // Return Value: -// nextNode to be lowered if tree is modified else returns nullptr -// -// Notes: -// Casts from float/double to a smaller int type are transformed as follows: -// GT_CAST(float/double, byte) = GT_CAST(GT_CAST(float/double, int32), byte) -// GT_CAST(float/double, sbyte) = GT_CAST(GT_CAST(float/double, int32), sbyte) -// GT_CAST(float/double, int16) = GT_CAST(GT_CAST(double/double, int32), int16) -// GT_CAST(float/double, uint16) = GT_CAST(GT_CAST(double/double, int32), uint16) -// -// Note that for the overflow conversions we still depend on helper calls and -// don't expect to see them here. -// i) GT_CAST(float/double, int type with overflow detection) +// None. // -GenTree* Lowering::LowerCast(GenTree* tree) +void Lowering::LowerCast(GenTree* tree) { - assert(tree->OperGet() == GT_CAST); + assert(tree->OperIs(GT_CAST)); JITDUMP("LowerCast for: "); DISPNODE(tree); @@ -995,17 +984,16 @@ GenTree* Lowering::LowerCast(GenTree* tree) if (varTypeIsFloating(srcType)) { + // Overflow casts should have been converted to helper call in morph. noway_assert(!tree->gtOverflow()); - assert(!varTypeIsSmall(dstType)); // fgMorphCast creates intermediate casts when converting from float to small - // int. + // Small types should have had an intermediate int cast inserted in morph. + assert(!varTypeIsSmall(dstType)); } assert(!varTypeIsSmall(srcType)); // Now determine if we have operands that should be contained. ContainCheckCast(tree->AsCast()); - - return nullptr; } //------------------------------------------------------------------------ diff --git a/src/runtime/src/coreclr/jit/lowerloongarch64.cpp b/src/runtime/src/coreclr/jit/lowerloongarch64.cpp index 6d062e63d9a..8edf0d098eb 100644 --- a/src/runtime/src/coreclr/jit/lowerloongarch64.cpp +++ b/src/runtime/src/coreclr/jit/lowerloongarch64.cpp @@ -515,21 +515,9 @@ void Lowering::LowerPutArgStkOrSplit(GenTreePutArgStk* putArgNode) // Return Value: // None. // -// Notes: -// Casts from float/double to a smaller int type are transformed as follows: -// GT_CAST(float/double, byte) = GT_CAST(GT_CAST(float/double, int32), byte) -// GT_CAST(float/double, sbyte) = GT_CAST(GT_CAST(float/double, int32), sbyte) -// GT_CAST(float/double, int16) = GT_CAST(GT_CAST(double/double, int32), int16) -// GT_CAST(float/double, uint16) = GT_CAST(GT_CAST(double/double, int32), uint16) -// -// Note that for the overflow conversions we still depend on helper calls and -// don't expect to see them here. -// i) GT_CAST(float/double, int type with overflow detection) -// - -GenTree* Lowering::LowerCast(GenTree* tree) +void Lowering::LowerCast(GenTree* tree) { - assert(tree->OperGet() == GT_CAST); + assert(tree->OperIs(GT_CAST)); JITDUMP("LowerCast for: "); DISPNODE(tree); @@ -541,17 +529,16 @@ GenTree* Lowering::LowerCast(GenTree* tree) if (varTypeIsFloating(srcType)) { + // Overflow casts should have been converted to helper call in morph. noway_assert(!tree->gtOverflow()); - assert(!varTypeIsSmall(dstType)); // fgMorphCast creates intermediate casts when converting from float to small - // int. + // Small types should have had an intermediate int cast inserted in morph. + assert(!varTypeIsSmall(dstType)); } assert(!varTypeIsSmall(srcType)); // Now determine if we have operands that should be contained. ContainCheckCast(tree->AsCast()); - - return nullptr; } //------------------------------------------------------------------------ diff --git a/src/runtime/src/coreclr/jit/lowerriscv64.cpp b/src/runtime/src/coreclr/jit/lowerriscv64.cpp index 6a37bbfdf0d..9f410e1e09a 100644 --- a/src/runtime/src/coreclr/jit/lowerriscv64.cpp +++ b/src/runtime/src/coreclr/jit/lowerriscv64.cpp @@ -504,21 +504,9 @@ void Lowering::LowerPutArgStkOrSplit(GenTreePutArgStk* putArgNode) // Return Value: // None. // -// Notes: -// Casts from float/double to a smaller int type are transformed as follows: -// GT_CAST(float/double, byte) = GT_CAST(GT_CAST(float/double, int32), byte) -// GT_CAST(float/double, sbyte) = GT_CAST(GT_CAST(float/double, int32), sbyte) -// GT_CAST(float/double, int16) = GT_CAST(GT_CAST(double/double, int32), int16) -// GT_CAST(float/double, uint16) = GT_CAST(GT_CAST(double/double, int32), uint16) -// -// Note that for the overflow conversions we still depend on helper calls and -// don't expect to see them here. -// i) GT_CAST(float/double, int type with overflow detection) -// - -GenTree* Lowering::LowerCast(GenTree* tree) +void Lowering::LowerCast(GenTree* tree) { - assert(tree->OperGet() == GT_CAST); + assert(tree->OperIs(GT_CAST)); JITDUMP("LowerCast for: "); DISPNODE(tree); @@ -530,17 +518,16 @@ GenTree* Lowering::LowerCast(GenTree* tree) if (varTypeIsFloating(srcType)) { + // Overflow casts should have been converted to helper call in morph. noway_assert(!tree->gtOverflow()); - assert(!varTypeIsSmall(dstType)); // fgMorphCast creates intermediate casts when converting from float to small - // int. + // Small types should have had an intermediate int cast inserted in morph. + assert(!varTypeIsSmall(dstType)); } assert(!varTypeIsSmall(srcType)); // Now determine if we have operands that should be contained. ContainCheckCast(tree->AsCast()); - - return nullptr; } //------------------------------------------------------------------------ diff --git a/src/runtime/src/coreclr/jit/lowerxarch.cpp b/src/runtime/src/coreclr/jit/lowerxarch.cpp index 41f05cafb6d..bf2b333fa05 100644 --- a/src/runtime/src/coreclr/jit/lowerxarch.cpp +++ b/src/runtime/src/coreclr/jit/lowerxarch.cpp @@ -107,30 +107,6 @@ GenTree* Lowering::LowerStoreIndir(GenTreeStoreInd* node) } ContainCheckStoreIndir(node); -#if defined(FEATURE_HW_INTRINSICS) - if (comp->IsBaselineVector512IsaSupportedOpportunistically() || - comp->compOpportunisticallyDependsOn(InstructionSet_AVX2)) - { - if (!node->Data()->IsCnsVec()) - { - return node->gtNext; - } - - if (!node->Data()->AsVecCon()->TypeIs(TYP_SIMD32, TYP_SIMD64)) - { - return node->gtNext; - } - - if (node->Data()->IsVectorAllBitsSet() || node->Data()->IsVectorZero()) - { - // To avoid some unexpected regression, this optimization only applies to non-all 1/0 constant vectors. - return node->gtNext; - } - - TryCompressConstVecData(node); - } -#endif - return node->gtNext; } @@ -847,38 +823,22 @@ void Lowering::LowerPutArgStk(GenTreePutArgStk* putArgStk) #endif // TARGET_X86 } -/* Lower GT_CAST(srcType, DstType) nodes. - * - * Casts from small int type to float/double are transformed as follows: - * GT_CAST(byte, float/double) = GT_CAST(GT_CAST(byte, int32), float/double) - * GT_CAST(sbyte, float/double) = GT_CAST(GT_CAST(sbyte, int32), float/double) - * GT_CAST(int16, float/double) = GT_CAST(GT_CAST(int16, int32), float/double) - * GT_CAST(uint16, float/double) = GT_CAST(GT_CAST(uint16, int32), float/double) - * - * Unless the EVEX conversion instructions are available, casts from Uint32 - * are morphed as follows by front-end and hence should not be seen here. - * GT_CAST(uint32, float/double) = GT_CAST(GT_CAST(uint32, long), float/double) - * - * - * Similarly casts from float/double to a smaller int type are transformed as follows: - * GT_CAST(float/double, byte) = GT_CAST(GT_CAST(float/double, int32), byte) - * GT_CAST(float/double, sbyte) = GT_CAST(GT_CAST(float/double, int32), sbyte) - * GT_CAST(float/double, int16) = GT_CAST(GT_CAST(double/double, int32), int16) - * GT_CAST(float/double, uint16) = GT_CAST(GT_CAST(double/double, int32), uint16) - * - * Note that for the following conversions we still depend on helper calls and - * don't expect to see them here. - * i) GT_CAST(float/double, uint64) when EVEX is not available - * ii) GT_CAST(float/double, int type with overflow detection) - */ -GenTree* Lowering::LowerCast(GenTree* tree) +//------------------------------------------------------------------------ +// LowerCast: Lower GT_CAST(srcType, DstType) nodes. +// +// Arguments: +// tree - GT_CAST node to be lowered +// +// Return Value: +// None. +// +void Lowering::LowerCast(GenTree* tree) { assert(tree->OperIs(GT_CAST)); - GenTree* castOp = tree->AsCast()->CastOp(); - var_types castToType = tree->CastToType(); - var_types dstType = castToType; - var_types srcType = castOp->TypeGet(); + GenTree* castOp = tree->AsCast()->CastOp(); + var_types dstType = tree->CastToType(); + var_types srcType = castOp->TypeGet(); // force the srcType to unsigned if GT_UNSIGNED flag is set if (tree->IsUnsigned()) @@ -886,345 +846,449 @@ GenTree* Lowering::LowerCast(GenTree* tree) srcType = varTypeToUnsigned(srcType); } - // We should not see the following casts unless directly supported by hardware, - // as they are expected to be lowered appropriately or converted into helper calls by front-end. - // srcType = float/double castToType = * and overflow detecting cast - // Reason: must be converted to a helper call - // srcType = float/double, castToType = ulong - // Reason: must be converted to a helper call - // srcType = float/double, castToType = byte/sbyte/ushort/short - // Reason: must have intermediate cast to int - // srcType = uint castToType = float/double - // Reason: uint -> float/double = uint -> long -> float/double if (varTypeIsFloating(srcType)) { + // Overflow casts should have been converted to helper call in morph. noway_assert(!tree->gtOverflow()); + // Small types should have had an intermediate int cast inserted in morph. assert(!varTypeIsSmall(dstType)); - assert(castToType != TYP_ULONG || comp->canUseEvexEncodingDebugOnly()); + // Long types should have been handled by helper call or in DecomposeLongs on x86. + assert(!varTypeIsLong(dstType) || TargetArchitecture::Is64Bit); } else if (srcType == TYP_UINT) { - assert(castToType != TYP_FLOAT || comp->canUseEvexEncodingDebugOnly()); + // uint->float casts should have an intermediate cast to long unless + // we have the EVEX unsigned conversion instructions available. + assert(dstType != TYP_FLOAT || comp->canUseEvexEncodingDebugOnly()); } -#if defined(TARGET_AMD64) - // Handle saturation logic for X64 - // Let InstructionSet_AVX10v2 pass through since it can handle the saturation - if (varTypeIsFloating(srcType) && varTypeIsIntegral(dstType) && !varTypeIsSmall(dstType) && +#ifdef FEATURE_HW_INTRINSICS + if (varTypeIsFloating(srcType) && varTypeIsIntegral(dstType) && !comp->compOpportunisticallyDependsOn(InstructionSet_AVX10v2)) { - // We should have filtered out float -> long conversion and - // converted it to float -> double -> long conversion. - assert((dstType != TYP_LONG) || (srcType != TYP_FLOAT)); + // If we don't have AVX10v2 saturating conversion instructions for + // floating->integral, we have to handle the saturation logic here. - // we should have handled overflow cases in morph itself - assert(!tree->gtOverflow()); + JITDUMP("LowerCast before:\n"); + DISPTREERANGE(BlockRange(), tree); - CorInfoType fieldType = (srcType == TYP_DOUBLE) ? CORINFO_TYPE_DOUBLE : CORINFO_TYPE_FLOAT; - GenTree* castOutput = nullptr; - LIR::Use castOpUse(BlockRange(), &(tree->AsCast()->CastOp()), tree); - ReplaceWithLclVar(castOpUse); - castOp = tree->AsCast()->CastOp(); - bool isV512Supported = false; - /*The code below is to introduce saturating conversions on X86/X64. - The C# equivalence of the code is given below --> - // Replace QNaN and SNaN with Zero - op1 = Avx512F.Fixup(op1, op1, Vector128.Create(0x88), 0); - // Convert from double to long, replacing any values that were greater than or equal to MaxValue - with MaxValue - // Values that were less than or equal to MinValue will already be MinValue - return Vector128.ConditionalSelect( - Vector128.LessThan(op1, Vector128.Create(long.MaxValue)).AsInt64(), - Avx512DQ.VL.ConvertToVector128Int64(op1), - Vector128.Create(long.MaxValue) - ); - */ - if (comp->compIsEvexOpportunisticallySupported(isV512Supported)) - { - // Clone the cast operand for usage. - GenTree* op1Clone1 = comp->gtClone(castOp); - BlockRange().InsertAfter(castOp, op1Clone1); - - // Generate the control table for VFIXUPIMMSD - // The behavior we want is to saturate negative values to 0. - GenTreeVecCon* tbl = comp->gtNewVconNode(TYP_SIMD16); - tbl->gtSimdVal.i32[0] = (varTypeIsUnsigned(dstType)) ? 0x08080088 : 0x00000088; - BlockRange().InsertAfter(op1Clone1, tbl); - - // get a zero int node for control table - GenTree* ctrlByte = comp->gtNewIconNode(0); - BlockRange().InsertAfter(tbl, ctrlByte); - - NamedIntrinsic fixupHwIntrinsicID = !isV512Supported ? NI_AVX10v1_FixupScalar : NI_AVX512F_FixupScalar; - if (varTypeIsUnsigned(dstType)) - { - // run vfixupimmsd base on table and no flags reporting - GenTree* oper1 = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, castOp, op1Clone1, tbl, ctrlByte, - fixupHwIntrinsicID, fieldType, 16); - BlockRange().InsertAfter(ctrlByte, oper1); - LowerNode(oper1); - - // Convert to scalar - // Here, we try to insert a Vector128 to Scalar node so that the input - // can be provided to the scalar cast - GenTree* oper2 = comp->gtNewSimdHWIntrinsicNode(srcType, oper1, NI_Vector128_ToScalar, fieldType, 16); - BlockRange().InsertAfter(oper1, oper2); - LowerNode(oper2); - - castOutput = comp->gtNewCastNode(genActualType(dstType), oper2, false, dstType); - BlockRange().InsertAfter(oper2, castOutput); - } - else - { - CorInfoType destFieldType = (dstType == TYP_INT) ? CORINFO_TYPE_INT : CORINFO_TYPE_LONG; - - ssize_t actualMaxVal = (dstType == TYP_INT) ? INT32_MAX : INT64_MAX; - - // run vfixupimmsd base on table and no flags reporting - GenTree* fixupVal = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, castOp, op1Clone1, tbl, ctrlByte, - fixupHwIntrinsicID, fieldType, 16); - BlockRange().InsertAfter(ctrlByte, fixupVal); - LowerNode(fixupVal); - - // get the max value vector - GenTree* maxValScalar = (srcType == TYP_DOUBLE) - ? comp->gtNewDconNodeD(static_cast(actualMaxVal)) - : comp->gtNewDconNodeF(static_cast(actualMaxVal)); - GenTree* maxVal = comp->gtNewSimdCreateBroadcastNode(TYP_SIMD16, maxValScalar, fieldType, 16); - BlockRange().InsertAfter(fixupVal, maxVal); - - GenTree* maxValDstTypeScalar = (dstType == TYP_INT) ? comp->gtNewIconNode(actualMaxVal, dstType) - : comp->gtNewLconNode(actualMaxVal); - GenTree* maxValDstType = - comp->gtNewSimdCreateBroadcastNode(TYP_SIMD16, maxValDstTypeScalar, destFieldType, 16); - BlockRange().InsertAfter(maxVal, maxValDstType); - - // usage 1 --> compare with max value of integer - GenTree* compMask = comp->gtNewSimdCmpOpNode(GT_GE, TYP_SIMD16, fixupVal, maxVal, fieldType, 16); - BlockRange().InsertAfter(maxValDstType, compMask); - - // convert fixupVal to local variable and clone it for further use - LIR::Use fixupValUse(BlockRange(), &(compMask->AsHWIntrinsic()->Op(1)), compMask); - ReplaceWithLclVar(fixupValUse); - fixupVal = compMask->AsHWIntrinsic()->Op(1); - GenTree* fixupValClone = comp->gtClone(fixupVal); - LowerNode(compMask); - BlockRange().InsertAfter(fixupVal, fixupValClone); - - GenTree* FixupValCloneScalar = - comp->gtNewSimdHWIntrinsicNode(srcType, fixupValClone, NI_Vector128_ToScalar, fieldType, 16); - BlockRange().InsertAfter(compMask, FixupValCloneScalar); - LowerNode(FixupValCloneScalar); - - // cast it - GenTreeCast* newCast = comp->gtNewCastNode(dstType, FixupValCloneScalar, false, dstType); - BlockRange().InsertAfter(FixupValCloneScalar, newCast); - - GenTree* newTree = comp->gtNewSimdCreateBroadcastNode(TYP_SIMD16, newCast, destFieldType, 16); - BlockRange().InsertAfter(newCast, newTree); - LowerNode(newTree); - - // usage 2 --> use the compared mask with input value and max value to blend - GenTree* control = comp->gtNewIconNode(0xCA); // (B & A) | (C & ~A) - BlockRange().InsertAfter(newTree, control); - GenTree* cndSelect = comp->gtNewSimdTernaryLogicNode(TYP_SIMD16, compMask, maxValDstType, newTree, - control, destFieldType, 16); - BlockRange().InsertAfter(control, cndSelect); - LowerNode(cndSelect); - - castOutput = - comp->gtNewSimdHWIntrinsicNode(dstType, cndSelect, NI_Vector128_ToScalar, destFieldType, 16); - BlockRange().InsertAfter(cndSelect, castOutput); - LowerNode(castOutput); - } - } - else if (varTypeIsSigned(dstType) && comp->compOpportunisticallyDependsOn(InstructionSet_SSE41)) - { - CorInfoType destFieldType = (dstType == TYP_INT) ? CORINFO_TYPE_INT : CORINFO_TYPE_LONG; - - ssize_t actualMaxVal = (dstType == TYP_INT) ? INT32_MAX : INT64_MAX; - - // create clones for usage - GenTree* castOpClone1 = comp->gtClone(castOp); - GenTree* castOpClone2 = comp->gtClone(castOp); - BlockRange().InsertAfter(castOp, castOpClone1); - BlockRange().InsertAfter(castOpClone1, castOpClone2); - - GenTree* oper = comp->gtNewSimdCreateBroadcastNode(TYP_SIMD16, castOp, fieldType, 16); - BlockRange().InsertAfter(castOpClone2, oper); - LowerNode(oper); - GenTree* op1Clone1 = comp->gtNewSimdCreateBroadcastNode(TYP_SIMD16, castOpClone1, fieldType, 16); - BlockRange().InsertAfter(oper, op1Clone1); - LowerNode(op1Clone1); - GenTree* op1Clone2 = comp->gtNewSimdCreateBroadcastNode(TYP_SIMD16, castOpClone2, fieldType, 16); - BlockRange().InsertAfter(op1Clone1, op1Clone2); - LowerNode(op1Clone2); - - // check NaN - GenTree* mask1 = comp->gtNewSimdCmpOpNode(GT_EQ, TYP_SIMD16, oper, op1Clone1, fieldType, 16); - BlockRange().InsertAfter(op1Clone2, mask1); - LowerNode(mask1); - // inp = inp & mask - GenTree* maskNaN = comp->gtNewSimdBinOpNode(GT_AND, TYP_SIMD16, op1Clone2, mask1, fieldType, 16); - BlockRange().InsertAfter(mask1, maskNaN); - LowerNode(maskNaN); - - // get the max value vector - GenTree* maxVal = (srcType == TYP_DOUBLE) ? comp->gtNewDconNodeD(static_cast(actualMaxVal)) - : comp->gtNewDconNodeF(static_cast(actualMaxVal)); - GenTree* maxValDup = - (dstType == TYP_INT) ? comp->gtNewIconNode(actualMaxVal) : comp->gtNewLconNode(actualMaxVal); - maxVal = comp->gtNewSimdCreateBroadcastNode(TYP_SIMD16, maxVal, fieldType, 16); - BlockRange().InsertAfter(maskNaN, maxVal); - maxValDup = comp->gtNewSimdCreateBroadcastNode(TYP_SIMD16, maxValDup, destFieldType, 16); - BlockRange().InsertAfter(maxVal, maxValDup); - - // usage 1 --> compare with max value of integer - GenTree* compMask = comp->gtNewSimdCmpOpNode(GT_GE, TYP_SIMD16, maskNaN, maxVal, fieldType, 16); - BlockRange().InsertAfter(maxValDup, compMask); - - // we will be using the maskNaN value twice - LIR::Use maskNaNUse(BlockRange(), &(compMask->AsHWIntrinsic()->Op(1)), compMask); - ReplaceWithLclVar(maskNaNUse); - maskNaN = compMask->AsHWIntrinsic()->Op(1); - GenTree* maskNaNClone = comp->gtClone(maskNaN); - LowerNode(compMask); - BlockRange().InsertAfter(maskNaN, maskNaNClone); - - // convert to scalar for conversion - GenTree* maskNaNCloneScalar = - comp->gtNewSimdHWIntrinsicNode(srcType, maskNaNClone, NI_Vector128_ToScalar, fieldType, 16); - BlockRange().InsertAfter(compMask, maskNaNCloneScalar); - LowerNode(maskNaNCloneScalar); - - // cast it - GenTreeCast* newCast = comp->gtNewCastNode(dstType, maskNaNCloneScalar, false, dstType); - BlockRange().InsertAfter(maskNaNCloneScalar, newCast); - GenTree* newTree = comp->gtNewSimdCreateBroadcastNode(TYP_SIMD16, newCast, destFieldType, 16); - BlockRange().InsertAfter(newCast, newTree); - LowerNode(newTree); - - // usage 2 --> use thecompared mask with input value and max value to blend - GenTree* cndSelect = comp->gtNewSimdCndSelNode(TYP_SIMD16, compMask, maxValDup, newTree, destFieldType, 16); - BlockRange().InsertAfter(newTree, cndSelect); - LowerNode(cndSelect); - - castOutput = comp->gtNewSimdHWIntrinsicNode(dstType, cndSelect, NI_Vector128_ToScalar, destFieldType, 16); - BlockRange().InsertAfter(cndSelect, castOutput); - LowerNode(castOutput); - } - else + CorInfoType srcBaseType = (srcType == TYP_FLOAT) ? CORINFO_TYPE_FLOAT : CORINFO_TYPE_DOUBLE; + LIR::Range castRange = LIR::EmptyRange(); + + // We'll be using SIMD instructions to fix up castOp before conversion. + // + // This creates the equivalent of the following C# code: + // var srcVec = Vector128.CreateScalarUnsafe(castOp); + + GenTree* srcVector = comp->gtNewSimdCreateScalarUnsafeNode(TYP_SIMD16, castOp, srcBaseType, 16); + castRange.InsertAtEnd(srcVector); + + if (srcVector->IsCnsVec()) { - // The remaining case not handled above should be conversion - // to TYP_UINT in case where SSE41 is supported. - // We should have converted float -> uint conversion to - // float -> double -> uint during morph. - assert((dstType == TYP_UINT) && comp->compIsaSupportedDebugOnly(InstructionSet_SSE41) && - (srcType != TYP_FLOAT)); - - ssize_t actualMaxVal = UINT32_MAX; - CorInfoType destFieldType = CORINFO_TYPE_LONG; - - GenTree* castOpClone1 = comp->gtClone(castOp); - GenTree* castOpClone2 = comp->gtClone(castOp); - GenTree* castOpClone3 = comp->gtClone(castOp); - BlockRange().InsertAfter(castOp, castOpClone1); - BlockRange().InsertAfter(castOpClone1, castOpClone2); - BlockRange().InsertAfter(castOpClone2, castOpClone3); - - GenTree* oper = comp->gtNewSimdCreateBroadcastNode(TYP_SIMD16, castOp, fieldType, 16); - BlockRange().InsertAfter(castOpClone3, oper); - LowerNode(oper); - GenTree* op1Clone1 = comp->gtNewSimdCreateBroadcastNode(TYP_SIMD16, castOpClone1, fieldType, 16); - BlockRange().InsertAfter(oper, op1Clone1); - LowerNode(op1Clone1); - GenTree* op1Clone2 = comp->gtNewSimdCreateBroadcastNode(TYP_SIMD16, castOpClone2, fieldType, 16); - BlockRange().InsertAfter(op1Clone1, op1Clone2); - LowerNode(op1Clone2); - GenTree* op1Clone3 = comp->gtNewSimdCreateBroadcastNode(TYP_SIMD16, castOpClone3, fieldType, 16); - BlockRange().InsertAfter(op1Clone2, op1Clone3); - LowerNode(op1Clone3); - - // get the max/min value vector - GenTree* minVal = comp->gtNewDconNodeD(static_cast(0)); - minVal = comp->gtNewSimdCreateBroadcastNode(TYP_SIMD16, minVal, fieldType, 16); - BlockRange().InsertAfter(op1Clone3, minVal); - GenTree* maxVal = comp->gtNewDconNodeD(static_cast(actualMaxVal)); - maxVal = comp->gtNewSimdCreateBroadcastNode(TYP_SIMD16, maxVal, fieldType, 16); - BlockRange().InsertAfter(minVal, maxVal); - - // check NaN - GenTree* mask1 = comp->gtNewSimdCmpOpNode(GT_EQ, TYP_SIMD16, oper, op1Clone1, fieldType, 16); - BlockRange().InsertAfter(maxVal, mask1); - LowerNode(mask1); - - // check negative - GenTree* mask2 = comp->gtNewSimdCmpOpNode(GT_GE, TYP_SIMD16, op1Clone2, minVal, fieldType, 16); - BlockRange().InsertAfter(mask1, mask2); - LowerNode(mask2); - - // and mask - GenTree* mask12 = comp->gtNewSimdBinOpNode(GT_AND, TYP_SIMD16, mask1, mask2, fieldType, 16); - BlockRange().InsertAfter(mask2, mask12); - LowerNode(mask12); - - // inp = inp & mask - GenTree* saturatedVal = comp->gtNewSimdBinOpNode(GT_AND, TYP_SIMD16, op1Clone3, mask12, fieldType, 16); - BlockRange().InsertAfter(mask12, saturatedVal); - LowerNode(saturatedVal); - - // compare with max value of uint - GenTree* mask3 = comp->gtNewSimdCmpOpNode(GT_GE, TYP_SIMD16, saturatedVal, maxVal, fieldType, 16); - BlockRange().InsertAfter(saturatedVal, mask3); - - // Convert both the operands of mask3 to local variables for reusage - LIR::Use saturatedValUse(BlockRange(), &(mask3->AsHWIntrinsic()->Op(1)), mask3); - ReplaceWithLclVar(saturatedValUse); - saturatedVal = mask3->AsHWIntrinsic()->Op(1); - GenTree* saturatedValDup = comp->gtClone(saturatedVal); - BlockRange().InsertAfter(saturatedVal, saturatedValDup); - - LIR::Use maxValUse(BlockRange(), &(mask3->AsHWIntrinsic()->Op(2)), mask3); - ReplaceWithLclVar(maxValUse); - maxVal = mask3->AsHWIntrinsic()->Op(2); - GenTree* maxValDup = comp->gtClone(maxVal); - LowerNode(mask3); - BlockRange().InsertAfter(maxVal, maxValDup); - - // Select based on mask3 - GenTree* castOpVal = - comp->gtNewSimdCndSelNode(TYP_SIMD16, mask3, maxValDup, saturatedValDup, fieldType, 16); - BlockRange().InsertAfter(mask3, castOpVal); - LowerNode(castOpVal); - - // scalar - GenTree* castOpValScalar = - comp->gtNewSimdHWIntrinsicNode(srcType, castOpVal, NI_Vector128_ToScalar, fieldType, 16); - BlockRange().InsertAfter(castOpVal, castOpValScalar); - LowerNode(castOpValScalar); - - // cast it - castOutput = comp->gtNewCastNode(TYP_INT, castOpValScalar, false, dstType); - BlockRange().InsertAfter(castOpValScalar, castOutput); - } - assert(castOutput != nullptr); - LIR::Use use; - if (BlockRange().TryGetUse(tree, &use)) + castOp->SetUnusedValue(); + } + + if (varTypeIsUnsigned(dstType) && comp->canUseEvexEncoding()) { - use.ReplaceWith(castOutput); + // EVEX unsigned conversion instructions saturate positive overflow properly, so as + // long as we fix up NaN and negative values, we can preserve the existing cast node. + // + // maxs[sd] will take the value from the second operand if the first operand's value is + // NaN, which allows us to fix up both negative and NaN values with a single instruction. + // + // This creates the equivalent of the following C# code: + // castOp = Sse.MaxScalar(srcVec, Vector128.Zero).ToScalar(); + + NamedIntrinsic maxScalarIntrinsic = (srcType == TYP_FLOAT) ? NI_SSE_MaxScalar : NI_SSE2_MaxScalar; + + GenTree* zero = comp->gtNewZeroConNode(TYP_SIMD16); + GenTree* fixupVal = + comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, srcVector, zero, maxScalarIntrinsic, srcBaseType, 16); + + GenTree* toScalar = comp->gtNewSimdToScalarNode(srcType, fixupVal, srcBaseType, 16); + + castRange.InsertAtEnd(zero); + castRange.InsertAtEnd(fixupVal); + castRange.InsertAtEnd(toScalar); + + tree->AsCast()->CastOp() = toScalar; } else { - castOutput->SetUnusedValue(); + assert(comp->IsBaselineSimdIsaSupportedDebugOnly()); + assert(!TargetArchitecture::Is64Bit || comp->compIsaSupportedDebugOnly(InstructionSet_SSE2_X64)); + + // We need to fix up NaN as well as handle possible overflow. Signed conversions + // return int/long.MinValue for any overflow, which is correct for saturation of + // negative, but the result must be replaced with MaxValue for positive overflow. + + CorInfoType dstBaseType = CORINFO_TYPE_UNDEF; + NamedIntrinsic convertIntrinsic = NI_Illegal; + GenTree* maxIntegralValue = nullptr; + GenTree* maxFloatingValue = comp->gtNewVconNode(TYP_SIMD16); + simd_t* maxFloatSimdVal = &maxFloatingValue->AsVecCon()->gtSimdVal; + + switch (dstType) + { + case TYP_INT: + { + dstBaseType = CORINFO_TYPE_INT; + maxIntegralValue = comp->gtNewIconNode(INT32_MAX); + if (srcType == TYP_FLOAT) + { + maxFloatSimdVal->f32[0] = 2147483648.0f; + convertIntrinsic = NI_SSE_ConvertToInt32WithTruncation; + } + else + { + maxFloatSimdVal->f64[0] = 2147483648.0; + convertIntrinsic = NI_SSE2_ConvertToInt32WithTruncation; + } + break; + } + case TYP_UINT: + { + dstBaseType = CORINFO_TYPE_UINT; + maxIntegralValue = comp->gtNewIconNode(static_cast(UINT32_MAX)); + if (srcType == TYP_FLOAT) + { + maxFloatSimdVal->f32[0] = 4294967296.0f; + convertIntrinsic = comp->compOpportunisticallyDependsOn(InstructionSet_SSE_X64) + ? NI_SSE_X64_ConvertToInt64WithTruncation + : NI_SSE2_ConvertToVector128Int32WithTruncation; + } + else + { + maxFloatSimdVal->f64[0] = 4294967296.0; + convertIntrinsic = comp->compOpportunisticallyDependsOn(InstructionSet_SSE2_X64) + ? NI_SSE2_X64_ConvertToInt64WithTruncation + : NI_SSE2_ConvertToVector128Int32WithTruncation; + } + break; + } + case TYP_LONG: + { + dstBaseType = CORINFO_TYPE_LONG; + maxIntegralValue = comp->gtNewLconNode(INT64_MAX); + if (srcType == TYP_FLOAT) + { + maxFloatSimdVal->f32[0] = 9223372036854775808.0f; + convertIntrinsic = NI_SSE_X64_ConvertToInt64WithTruncation; + } + else + { + maxFloatSimdVal->f64[0] = 9223372036854775808.0; + convertIntrinsic = NI_SSE2_X64_ConvertToInt64WithTruncation; + } + break; + } + case TYP_ULONG: + { + dstBaseType = CORINFO_TYPE_ULONG; + maxIntegralValue = comp->gtNewLconNode(static_cast(UINT64_MAX)); + if (srcType == TYP_FLOAT) + { + maxFloatSimdVal->f32[0] = 18446744073709551616.0f; + convertIntrinsic = NI_SSE_X64_ConvertToInt64WithTruncation; + } + else + { + maxFloatSimdVal->f64[0] = 18446744073709551616.0; + convertIntrinsic = NI_SSE2_X64_ConvertToInt64WithTruncation; + } + break; + } + default: + { + unreached(); + } + } + + // We will use the input value at least twice, so we preemptively replace it with a lclVar. + LIR::Use srcUse; + LIR::Use::MakeDummyUse(castRange, srcVector, &srcUse); + srcUse.ReplaceWithLclVar(comp); + srcVector = srcUse.Def(); + + GenTree* srcClone = nullptr; + GenTree* convertResult = nullptr; + + if (varTypeIsSigned(dstType)) + { + // Fix up NaN values before conversion. Saturation is handled after conversion, + // because MaxValue may not be precisely representable in the floating format. + // + // This creates the equivalent of the following C# code: + // var nanMask = Sse.CompareScalarOrdered(srcVec, srcVec); + // var fixupVal = Sse.And(srcVec, nanMask); + // convertResult = Sse.ConvertToInt32WithTruncation(fixupVal); + + NamedIntrinsic compareNaNIntrinsic = + (srcType == TYP_FLOAT) ? NI_SSE_CompareScalarOrdered : NI_SSE2_CompareScalarOrdered; + + srcClone = comp->gtClone(srcVector); + GenTree* nanMask = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, srcVector, srcClone, compareNaNIntrinsic, + srcBaseType, 16); + + castRange.InsertAtEnd(srcClone); + castRange.InsertAtEnd(nanMask); + + srcClone = comp->gtClone(srcVector); + GenTree* fixupVal = comp->gtNewSimdBinOpNode(GT_AND, TYP_SIMD16, nanMask, srcClone, srcBaseType, 16); + + castRange.InsertAtEnd(srcClone); + castRange.InsertAtEnd(fixupVal); + + convertResult = comp->gtNewSimdHWIntrinsicNode(dstType, fixupVal, convertIntrinsic, srcBaseType, 16); + } + else + { + // maxs[sd] will take the value from the second operand if the first operand's value is + // NaN, which allows us to fix up both negative and NaN values with a single instruction. + // + // This creates the equivalent of the following C# code: + // var fixupVal = Sse.MaxScalar(srcVec, Vector128.Zero); + + NamedIntrinsic maxScalarIntrinsic = (srcType == TYP_FLOAT) ? NI_SSE_MaxScalar : NI_SSE2_MaxScalar; + + GenTree* zero = comp->gtNewZeroConNode(TYP_SIMD16); + GenTree* fixupVal = + comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, srcVector, zero, maxScalarIntrinsic, srcBaseType, 16); + + castRange.InsertAtEnd(zero); + castRange.InsertAtEnd(fixupVal); + + if ((dstType == TYP_UINT) && ((convertIntrinsic == NI_SSE_X64_ConvertToInt64WithTruncation) || + (convertIntrinsic == NI_SSE2_X64_ConvertToInt64WithTruncation))) + { + // On x64, we can use long conversion to handle uint directly. + convertResult = + comp->gtNewSimdHWIntrinsicNode(TYP_LONG, fixupVal, convertIntrinsic, srcBaseType, 16); + } + else + { + // We're doing a conversion that isn't supported directly by hardware. We will emulate + // the unsigned conversion by using the signed instruction on both the fixed-up input + // value and a negative value that has the same bit representation when converted to + // integer. If the conversion overflows as a signed integer, the negative conversion + // result is selected. + // + // This creates the equivalent of the following C# code: + // var wrapVal = Sse.SubtractScalar(srcVec, maxFloatingValue); + + NamedIntrinsic subtractIntrinsic = + (srcType == TYP_FLOAT) ? NI_SSE_SubtractScalar : NI_SSE2_SubtractScalar; + + // We're going to use maxFloatingValue twice, so replace the constant with a lclVar. + castRange.InsertAtEnd(maxFloatingValue); + + LIR::Use maxFloatUse; + LIR::Use::MakeDummyUse(castRange, maxFloatingValue, &maxFloatUse); + maxFloatUse.ReplaceWithLclVar(comp); + maxFloatingValue = maxFloatUse.Def(); + + GenTree* floorVal = comp->gtClone(srcVector); + castRange.InsertAtEnd(floorVal); + + if ((srcType == TYP_DOUBLE) && (dstType == TYP_UINT)) + { + // This technique works only if the truncating conversion of the positive and negative + // values causes them to round in the same direction. i.e. there is no rounding, because + // we have a whole number. This is always true if the exponent is larger than the number + // of significand bits, which will always be the case for double->ulong or float->uint. + // + // For double->uint, the double has enough precision to exactly represent any whole number + // in range, with bits left over. e.g. we might have a value of 4294967295.9999995. + // We must, therefore, truncate the value before wrapping it to negative. + + if (comp->compOpportunisticallyDependsOn(InstructionSet_SSE41)) + { + // This creates the equivalent of the following C# code: + // floorVal = Sse41.RoundToZeroScalar(srcVector); + + floorVal = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, floorVal, NI_SSE41_RoundToZeroScalar, + srcBaseType, 16); + castRange.InsertAtEnd(floorVal); + } + else + { + // We don't have `roundsd` available, but we can truncate the value by simply zeroing out + // the low 21 bits of the double. This works because we know we will only use the negative + // value when the exponent is exactly 31, meaning 31 of the 52 bits in the significand are + // used for the whole portion of the number, and the remaining 21 bits are fractional. + // + // This creates the equivalent of the following C# code: + // floorVal = ((srcVector.AsUInt64() >>> 21) << 21).AsDouble(); + + GenTree* twentyOne = comp->gtNewIconNode(21); + GenTree* rightShift = comp->gtNewSimdBinOpNode(GT_RSZ, TYP_SIMD16, floorVal, twentyOne, + CORINFO_TYPE_ULONG, 16); + castRange.InsertAtEnd(twentyOne); + castRange.InsertAtEnd(rightShift); + + twentyOne = comp->gtClone(twentyOne); + floorVal = comp->gtNewSimdBinOpNode(GT_LSH, TYP_SIMD16, rightShift, twentyOne, + CORINFO_TYPE_ULONG, 16); + castRange.InsertAtEnd(twentyOne); + castRange.InsertAtEnd(floorVal); + } + } + + GenTree* wrapVal = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, floorVal, maxFloatingValue, + subtractIntrinsic, srcBaseType, 16); + castRange.InsertAtEnd(wrapVal); + + maxFloatingValue = comp->gtClone(maxFloatingValue); + + if (dstType == TYP_UINT) + { + // We can keep the conversion results in SIMD registers to make selection of the + // correct result simpler. + // + // This creates the equivalent of the following C# code: + // var result = Sse2.ConvertToVector128Int32WithTruncation(fixupVal); + // var negated = Sse2.ConvertToVector128Int32WithTruncation(wrapVal); + + GenTree* result = + comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, fixupVal, convertIntrinsic, srcBaseType, 16); + GenTree* negated = + comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, wrapVal, convertIntrinsic, srcBaseType, 16); + + castRange.InsertAtEnd(result); + castRange.InsertAtEnd(negated); + + // We need the result twice -- one for the mask bit and one for the blend. + LIR::Use resultUse; + LIR::Use::MakeDummyUse(castRange, result, &resultUse); + resultUse.ReplaceWithLclVar(comp); + result = resultUse.Def(); + + GenTree* resultClone = comp->gtClone(result); + castRange.InsertAtEnd(resultClone); + + if (comp->compOpportunisticallyDependsOn(InstructionSet_SSE41)) + { + // If the conversion of the fixed-up value overflowed, the result wil be + // int.MinValue. Since `blendvps` uses only the MSB for result selection, + // this is adequate to force selection of the negated result. + // + // This creates the equivalent of the following C# code: + // convertResult = Sse41.BlendVariable(result, negated, result); + + convertResult = + comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, result, negated, resultClone, + NI_SSE41_BlendVariable, CORINFO_TYPE_FLOAT, 16); + } + else + { + // If we can't use `blendvps`, we do a bit-wise selection. This works + // using only and+or because if we choose the negated value, both it + // and the overflowed result have MSB set. + // + // This creates the equivalent of the following C# code: + // var mask = Sse2.ShiftRightArithmetic(result, 31); + // convertResult = Sse.Or(result, Sse.And(negated, mask)); + + GenTree* thirtyOne = comp->gtNewIconNode(31); + GenTree* mask = + comp->gtNewSimdBinOpNode(GT_RSH, TYP_SIMD16, result, thirtyOne, CORINFO_TYPE_INT, 16); + GenTree* andMask = + comp->gtNewSimdBinOpNode(GT_AND, TYP_SIMD16, mask, negated, dstBaseType, 16); + + castRange.InsertAtEnd(thirtyOne); + castRange.InsertAtEnd(mask); + castRange.InsertAtEnd(andMask); + + convertResult = + comp->gtNewSimdBinOpNode(GT_OR, TYP_SIMD16, andMask, resultClone, dstBaseType, 16); + } + + // Because the results are in a SIMD register, we need to ToScalar() them out. + castRange.InsertAtEnd(convertResult); + convertResult = comp->gtNewSimdToScalarNode(TYP_INT, convertResult, dstBaseType, 16); + } + else + { + assert(dstType == TYP_ULONG); + + // We're emulating floating->ulong conversion on x64. The logic is the same as for + // uint on x86, except that we don't have conversion instructions that keep the + // results in SIMD registers, so we do the final result selection in scalar code. + // + // This creates the equivalent of the following C# code: + // long result = Sse.X64.ConvertToInt64WithTruncation(fixupVal); + // long negated = Sse.X64.ConvertToInt64WithTruncation(wrapVal); + // convertResult = (ulong)(result | (negated & (result >> 63))); + + GenTree* result = + comp->gtNewSimdHWIntrinsicNode(TYP_LONG, fixupVal, convertIntrinsic, srcBaseType, 16); + GenTree* negated = + comp->gtNewSimdHWIntrinsicNode(TYP_LONG, wrapVal, convertIntrinsic, srcBaseType, 16); + + castRange.InsertAtEnd(result); + castRange.InsertAtEnd(negated); + + // We need the result twice -- once for the mask bit and once for the blend. + LIR::Use resultUse; + LIR::Use::MakeDummyUse(castRange, result, &resultUse); + resultUse.ReplaceWithLclVar(comp); + result = resultUse.Def(); + + GenTree* sixtyThree = comp->gtNewIconNode(63); + GenTree* mask = comp->gtNewOperNode(GT_RSH, TYP_LONG, result, sixtyThree); + GenTree* andMask = comp->gtNewOperNode(GT_AND, TYP_LONG, mask, negated); + GenTree* resultClone = comp->gtClone(result); + + castRange.InsertAtEnd(sixtyThree); + castRange.InsertAtEnd(mask); + castRange.InsertAtEnd(andMask); + castRange.InsertAtEnd(resultClone); + + convertResult = comp->gtNewOperNode(GT_OR, TYP_LONG, andMask, resultClone); + } + } + } + + // Now we handle saturation of the result for positive overflow. + // + // This creates the equivalent of the following C# code: + // bool isOverflow = Sse.CompareScalarUnorderedGreaterThanOrEqual(srcVec, maxFloatingValue); + // return isOverflow ? maxIntegralValue : convertResult; + + NamedIntrinsic compareIntrinsic = (srcType == TYP_FLOAT) ? NI_SSE_CompareScalarUnorderedGreaterThanOrEqual + : NI_SSE2_CompareScalarUnorderedGreaterThanOrEqual; + + // These nodes were all created above but not used until now. + castRange.InsertAtEnd(maxFloatingValue); + castRange.InsertAtEnd(maxIntegralValue); + castRange.InsertAtEnd(convertResult); + + srcClone = comp->gtClone(srcVector); + GenTree* compareMax = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, srcClone, maxFloatingValue, + compareIntrinsic, srcBaseType, 16); + GenTree* select = comp->gtNewConditionalNode(GT_SELECT, compareMax, maxIntegralValue, convertResult, + genActualType(dstType)); + + castRange.InsertAtEnd(srcClone); + castRange.InsertAtEnd(compareMax); + castRange.InsertAtEnd(select); + + // The original cast becomes a no-op, because its input is already the correct type. + tree->AsCast()->CastOp() = select; } - BlockRange().Remove(tree); - return castOutput->gtNext; + + LIR::ReadOnlyRange lowerRange(castRange.FirstNode(), castRange.LastNode()); + BlockRange().InsertBefore(tree, std::move(castRange)); + + JITDUMP("LowerCast after:\n"); + DISPTREERANGE(BlockRange(), tree); + + LowerRange(lowerRange); } -#endif // TARGET_AMD64 +#endif // FEATURE_HW_INTRINSICS // Now determine if we have operands that should be contained. ContainCheckCast(tree->AsCast()); - return nullptr; } #ifdef FEATURE_HW_INTRINSICS @@ -4145,7 +4209,7 @@ GenTree* Lowering::LowerHWIntrinsicCreate(GenTreeHWIntrinsic* node) BlockRange().Remove(node); - return LowerNode(vecCon); + return vecCon->gtNext; } else if (argCnt == 1) { @@ -8921,9 +8985,6 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* parentNode, GenTre case NI_AVX2_ConvertToVector256Int16: case NI_AVX2_ConvertToVector256Int32: case NI_AVX2_ConvertToVector256Int64: - case NI_AVX2_BroadcastVector128ToVector256: - case NI_AVX512F_BroadcastVector128ToVector512: - case NI_AVX512F_BroadcastVector256ToVector512: { // These can have either pointer or vector operands. For the pointer case, we can't check // size, so just assume it matches. Otherwise, do normal size check based on tuple type. @@ -9484,83 +9545,6 @@ void Lowering::TryFoldCnsVecForEmbeddedBroadcast(GenTreeHWIntrinsic* parentNode, MakeSrcContained(parentNode, childNode); } -//---------------------------------------------------------------------------------------------- -// TryCompressConstVecData: -// Try to compress the constant vector input if it has duplicated parts and can be optimized by -// broadcast -// -// Arguments: -// node - the storeind node. -// -// Return: -// return true if compress success. -void Lowering::TryCompressConstVecData(GenTreeStoreInd* node) -{ - assert(node->Data()->IsCnsVec()); - assert(node->Data()->AsVecCon()->TypeIs(TYP_SIMD32, TYP_SIMD64)); - - GenTreeVecCon* vecCon = node->Data()->AsVecCon(); - GenTreeHWIntrinsic* broadcast = nullptr; - - if (vecCon->TypeIs(TYP_SIMD32)) - { - assert(comp->compOpportunisticallyDependsOn(InstructionSet_AVX2)); - if (vecCon->gtSimd32Val.v128[0] == vecCon->gtSimdVal.v128[1]) - { - simd16_t simd16Val = {}; - simd16Val.f64[0] = vecCon->gtSimd32Val.f64[0]; - simd16Val.f64[1] = vecCon->gtSimd32Val.f64[1]; - GenTreeVecCon* compressedVecCon = comp->gtNewVconNode(TYP_SIMD16); - memcpy(&compressedVecCon->gtSimdVal, &simd16Val, sizeof(simd16_t)); - BlockRange().InsertBefore(node->Data(), compressedVecCon); - BlockRange().Remove(vecCon); - broadcast = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD32, compressedVecCon, - NI_AVX2_BroadcastVector128ToVector256, CORINFO_TYPE_UINT, 32); - } - } - else - { - assert(vecCon->TypeIs(TYP_SIMD64)); - assert(comp->IsBaselineVector512IsaSupportedOpportunistically()); - if (vecCon->gtSimd64Val.v128[0] == vecCon->gtSimd64Val.v128[1] && - vecCon->gtSimd64Val.v128[0] == vecCon->gtSimd64Val.v128[2] && - vecCon->gtSimd64Val.v128[0] == vecCon->gtSimd64Val.v128[3]) - { - simd16_t simd16Val = {}; - simd16Val.f64[0] = vecCon->gtSimd64Val.f64[0]; - simd16Val.f64[1] = vecCon->gtSimd64Val.f64[1]; - GenTreeVecCon* compressedVecCon = comp->gtNewVconNode(TYP_SIMD16); - memcpy(&compressedVecCon->gtSimdVal, &simd16Val, sizeof(simd16_t)); - BlockRange().InsertBefore(node->Data(), compressedVecCon); - BlockRange().Remove(vecCon); - broadcast = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD64, compressedVecCon, - NI_AVX512F_BroadcastVector128ToVector512, CORINFO_TYPE_UINT, 64); - } - else if (vecCon->gtSimd64Val.v256[0] == vecCon->gtSimd64Val.v256[1]) - { - simd32_t simd32Val = {}; - simd32Val.v128[0] = vecCon->gtSimd32Val.v128[0]; - simd32Val.v128[1] = vecCon->gtSimd32Val.v128[1]; - GenTreeVecCon* compressedVecCon = comp->gtNewVconNode(TYP_SIMD32); - memcpy(&compressedVecCon->gtSimdVal, &simd32Val, sizeof(simd32_t)); - BlockRange().InsertBefore(node->Data(), compressedVecCon); - BlockRange().Remove(vecCon); - broadcast = - comp->gtNewSimdHWIntrinsicNode(TYP_SIMD64, compressedVecCon, NI_AVX512F_BroadcastVector256ToVector512, - CORINFO_TYPE_ULONG, 64); - } - } - - if (broadcast == nullptr) - { - return; - } - - BlockRange().InsertBefore(node, broadcast); - node->Data() = broadcast; - LowerNode(broadcast); -} - //------------------------------------------------------------------------ // TryMakeSrcContainedOrRegOptional: Tries to make "childNode" a contained or regOptional node // @@ -9814,20 +9798,6 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) break; } - case NI_AVX2_BroadcastVector128ToVector256: - case NI_AVX512F_BroadcastVector128ToVector512: - case NI_AVX512F_BroadcastVector256ToVector512: - { - if (node->OperIsMemoryLoad()) - { - ContainCheckHWIntrinsicAddr(node, op1, /* conservative maximum */ 32); - return; - } - - assert(op1->IsCnsVec()); - break; - } - case NI_AVX512F_ConvertToVector256Int32: case NI_AVX512F_ConvertToVector256UInt32: case NI_AVX512F_VL_ConvertToVector128UInt32: diff --git a/src/runtime/src/coreclr/jit/morph.cpp b/src/runtime/src/coreclr/jit/morph.cpp index 3792efd0602..57ae762bc73 100644 --- a/src/runtime/src/coreclr/jit/morph.cpp +++ b/src/runtime/src/coreclr/jit/morph.cpp @@ -299,21 +299,14 @@ GenTree* Compiler::fgMorphExpandCast(GenTreeCast* tree) // This goes through helper and hence src needs to be converted to double. && tree->gtOverflow() #elif defined(TARGET_AMD64) - // Amd64: src = float, dst = uint64 or overflow conversion. - // src needs to be converted to double except for the following cases - // dstType = int/uint/ulong for AVX512F - // dstType = int for SSE41 - // For pre-SSE41, the all src is converted to TYP_DOUBLE - // and goes through helpers. - && - (tree->gtOverflow() || (dstType == TYP_LONG && !compOpportunisticallyDependsOn(InstructionSet_AVX10v2)) || - !(canUseEvexEncoding() || (dstType == TYP_INT && compOpportunisticallyDependsOn(InstructionSet_SSE41)))) + // Amd64: src = float, dst = overflow conversion or SSE2 is not enabled + && (tree->gtOverflow() || !IsBaselineSimdIsaSupported()) #elif defined(TARGET_ARM) // Arm: src = float, dst = int64/uint64 or overflow conversion. && (tree->gtOverflow() || varTypeIsLong(dstType)) #else - // x86: src = float, dst = uint32/int64/uint64 or overflow conversion. - && (tree->gtOverflow() || varTypeIsIntegral(dstType)) + // x86: src = float, dst = int64/uint64 or overflow conversion or SSE2 is not enabled + && (tree->gtOverflow() || varTypeIsLong(dstType) || !IsBaselineSimdIsaSupported()) #endif ) { @@ -339,25 +332,12 @@ GenTree* Compiler::fgMorphExpandCast(GenTreeCast* tree) #if defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) return nullptr; #else -#if defined(TARGET_AMD64) - // Following nodes are handled when lowering the nodes - // float -> ulong/uint/int/long for AVX10.2 - // double -> ulong/uint/int/long for AVX10.2 - // float -> ulong/uint/int for AVX512F - // double -> ulong/uint/long/int for AVX512F - // float -> int for SSE41 - // double -> int/uint/long for SSE41 - // For all other conversions, we use helper functions. - if (canUseEvexEncoding() || - ((dstType != TYP_ULONG) && compOpportunisticallyDependsOn(InstructionSet_SSE41))) - { - if (tree->CastOp() != oper) - { - tree->CastOp() = oper; - } +#if defined(TARGET_XARCH) + if (IsBaselineSimdIsaSupported() && (!varTypeIsLong(dstType) || TargetArchitecture::Is64Bit)) + { return nullptr; } -#endif // TARGET_AMD64 +#endif // TARGET_XARCH switch (dstType) { case TYP_INT: @@ -417,11 +397,16 @@ GenTree* Compiler::fgMorphExpandCast(GenTreeCast* tree) // Because there is no IL instruction conv.r4.un, uint/ulong -> float // casts are always imported as CAST(float <- CAST(double <- uint/ulong)). // We can usually eliminate the redundant intermediate cast as an optimization. + // // AArch and xarch+EVEX have instructions that can cast directly from - // all integers (except for longs on 32-bit of course) to floats. + // all integers (except for longs on ARM32) to floats. // On x64, we also have the option of widening uint -> long and // using the signed conversion instructions, and ulong -> float/double // is handled directly in codegen, so we can allow all casts. + // + // This logic will also catch CAST(float <- CAST(double <- float)) + // and reduce it to CAST(float <- float), which is handled in codegen as + // an optional mov. else if ((dstType == TYP_FLOAT) && (srcType == TYP_DOUBLE) && oper->OperIs(GT_CAST) #ifndef TARGET_64BIT && !varTypeIsLong(oper->AsCast()->CastOp()) @@ -481,6 +466,15 @@ GenTree* Compiler::fgMorphExpandCast(GenTreeCast* tree) #endif // TARGET_AMD64 #ifdef TARGET_X86 +#ifdef FEATURE_HW_INTRINSICS + else if (varTypeIsLong(srcType) && varTypeIsFloating(dstType) && canUseEvexEncoding()) + { + // We can handle these casts directly using SIMD instructions. + // The transform to SIMD is done in DecomposeLongs. + return nullptr; + } +#endif // FEATURE_HW_INTRINSICS + // Do we have to do two step U4/8 -> R4/8 ? else if (tree->IsUnsigned() && varTypeIsFloating(dstType)) { @@ -494,7 +488,7 @@ GenTree* Compiler::fgMorphExpandCast(GenTreeCast* tree) { oper = gtNewCastNode(TYP_LONG, oper, true, TYP_LONG); oper->gtFlags |= (tree->gtFlags & (GTF_OVERFLOW | GTF_EXCEPT)); - tree->gtFlags &= ~GTF_UNSIGNED; + tree->ClearUnsigned(); return fgMorphCastIntoHelper(tree, CORINFO_HELP_LNG2DBL, oper); } } diff --git a/src/runtime/src/coreclr/jit/objectalloc.cpp b/src/runtime/src/coreclr/jit/objectalloc.cpp index 347520f1c70..b88dc448ef6 100644 --- a/src/runtime/src/coreclr/jit/objectalloc.cpp +++ b/src/runtime/src/coreclr/jit/objectalloc.cpp @@ -25,14 +25,14 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // comp - compiler instance // // Notes: -// Runs only if Compiler::optMethodFlags has flag OMF_HAS_NEWOBJ set. +// Runs only if Compiler::optMethodFlags has flag OMF_HAS_NEWOBJ or OMF_HAS_NEWARR. // -// Builds a connection graph where nodes mostly represent local vars, -// showing how locals can assign values to one another. +// Builds a connection graph where nodes mostly represent gc typed local vars, +// showing how these locals can assign values to one another. // -// The graph also includes a few abstract node types: a node representing -// an unknown source of values, and (pseudo local) nodes representing -// assignments that only happen under particular conditions. +// The graph also includes a abstract node types: a node representing an unknown source of values, +// pseudo nodes representing assignments that only happen under particular conditions, +// and nodes representing fields of local structs. // ObjectAllocator::ObjectAllocator(Compiler* comp) : Phase(comp, PHASE_ALLOCATE_OBJECTS) @@ -41,16 +41,14 @@ ObjectAllocator::ObjectAllocator(Compiler* comp) , m_isR2R(comp->IsReadyToRun()) , m_bvCount(0) , m_bitVecTraits(BitVecTraits(comp->lvaCount, comp)) - , m_unknownSourceLocalNum(BAD_VAR_NUM) , m_unknownSourceIndex(BAD_VAR_NUM) , m_HeapLocalToStackLocalMap(comp->getAllocator(CMK_ObjectAllocator)) - , m_EnumeratorLocalToPseudoLocalMap(comp->getAllocator(CMK_ObjectAllocator)) + , m_EnumeratorLocalToPseudoIndexMap(comp->getAllocator(CMK_ObjectAllocator)) , m_CloneMap(comp->getAllocator(CMK_ObjectAllocator)) , m_nextLocalIndex(0) - , m_firstPseudoLocalNum(BAD_VAR_NUM) - , m_firstPseudoLocalIndex(BAD_VAR_NUM) - , m_numPseudoLocals(0) - , m_maxPseudoLocals(0) + , m_firstPseudoIndex(BAD_VAR_NUM) + , m_numPseudos(0) + , m_maxPseudos(0) , m_regionsToClone(0) , m_trackFields(false) { @@ -96,60 +94,20 @@ bool ObjectAllocator::IsTrackedLocal(unsigned lclNum) } //------------------------------------------------------------------------ -// HasIndex: see if a given local has a tracking index -// -// Arguments: -// lclNum -- local to query -// -// Returns: -// true if so -// -bool ObjectAllocator::HasIndex(unsigned lclNum) -{ - if (lclNum < comp->lvaCount) - { - LclVarDsc* const varDsc = comp->lvaGetDesc(lclNum); - return varDsc->lvTracked; - } - - if ((lclNum >= m_firstPseudoLocalNum) && (lclNum < m_bvCount)) - { - return true; - } - - return false; -} - -//------------------------------------------------------------------------ -// LocalToIndex: get the bit vector index for a local or pseudo-local +// LocalToIndex: get the bit vector index for a local // // Arguments: -// lclNum -- local var num or pseudo local var num +// lclNum -- local var num // // Returns: -// bvIndex to use +// bvIndex to use, or BAD_VAR_NUM if local is not tracked // unsigned ObjectAllocator::LocalToIndex(unsigned lclNum) { - unsigned result = BAD_VAR_NUM; - - if (lclNum < m_firstPseudoLocalNum) - { - assert(IsTrackedLocal(lclNum)); - LclVarDsc* const varDsc = comp->lvaGetDesc(lclNum); - result = varDsc->lvVarIndex; - } - else if (lclNum == m_unknownSourceLocalNum) - { - result = m_unknownSourceIndex; - } - else - { - result = m_firstPseudoLocalIndex + (lclNum - m_firstPseudoLocalNum); - } - + assert(IsTrackedLocal(lclNum)); + LclVarDsc* const varDsc = comp->lvaGetDesc(lclNum); + unsigned const result = varDsc->lvVarIndex; assert(result < m_bvCount); - return result; } @@ -160,23 +118,18 @@ unsigned ObjectAllocator::LocalToIndex(unsigned lclNum) // bvIndex -- bit vector index // // Returns: -// local num +// local num or BAD_VAR_NUM if index is not a tracked local var // unsigned ObjectAllocator::IndexToLocal(unsigned bvIndex) { assert(bvIndex < m_bvCount); unsigned result = BAD_VAR_NUM; - if (bvIndex < m_firstPseudoLocalIndex) + if (bvIndex < m_firstPseudoIndex) { result = comp->lvaTrackedToVarNum[bvIndex]; assert(IsTrackedLocal(result)); } - else - { - result = m_firstPseudoLocalNum + (bvIndex - m_firstPseudoLocalIndex); - } - return result; } @@ -192,10 +145,25 @@ unsigned ObjectAllocator::IndexToLocal(unsigned bvIndex) // void ObjectAllocator::DumpIndex(unsigned bvIndex) { - const unsigned lclNum = IndexToLocal(bvIndex); - const bool isLocalVar = (lclNum < m_firstPseudoLocalNum); - const bool isUnknown = (lclNum == m_unknownSourceLocalNum); - printf(" %c%02u", isUnknown ? 'U' : isLocalVar ? 'V' : 'P', lclNum); + if (bvIndex < m_firstPseudoIndex) + { + printf(" V%02u", IndexToLocal(bvIndex)); + return; + } + + if (bvIndex < m_unknownSourceIndex) + { + printf(" P%02u", bvIndex); + return; + } + + if (bvIndex == m_unknownSourceIndex) + { + printf(" U%02u", bvIndex); + return; + } + + printf(" ?%02u", bvIndex); } #endif @@ -279,10 +247,22 @@ PhaseStatus ObjectAllocator::DoPhase() // // Arguments: // lclNum - Escaping pointing local variable number - +// void ObjectAllocator::MarkLclVarAsEscaping(unsigned int lclNum) { const unsigned bvIndex = LocalToIndex(lclNum); + MarkIndexAsEscaping(bvIndex); +} + +//------------------------------------------------------------------------------ +// MarkIndexAsEscaping : Mark resource as escaping. +// +// +// Arguments: +// index - bv index for the resource +// +void ObjectAllocator::MarkIndexAsEscaping(unsigned int bvIndex) +{ BitVecOps::AddElemD(&m_bitVecTraits, m_EscapingPointers, bvIndex); } @@ -293,11 +273,23 @@ void ObjectAllocator::MarkLclVarAsEscaping(unsigned int lclNum) // // Arguments: // lclNum - Possibly stack-object-pointing local variable number - +// void ObjectAllocator::MarkLclVarAsPossiblyStackPointing(unsigned int lclNum) { const unsigned bvIndex = LocalToIndex(lclNum); - JITDUMP("Marking V%02u (0x%02x) as possibly stack-pointing\n", lclNum, bvIndex); + MarkIndexAsPossiblyStackPointing(bvIndex); +} + +//------------------------------------------------------------------------------ +// MarkIndexAsPossiblyStackPointing : Mark resource as possibly pointing +// to a stack-allocated object. +// +// +// Arguments: +// index - bv index for the resource +// +void ObjectAllocator::MarkIndexAsPossiblyStackPointing(unsigned int bvIndex) +{ BitVecOps::AddElemD(&m_bitVecTraits, m_PossiblyStackPointingPointers, bvIndex); } @@ -308,11 +300,23 @@ void ObjectAllocator::MarkLclVarAsPossiblyStackPointing(unsigned int lclNum) // // Arguments: // lclNum - Definitely stack-object-pointing local variable number - +// void ObjectAllocator::MarkLclVarAsDefinitelyStackPointing(unsigned int lclNum) { const unsigned bvIndex = LocalToIndex(lclNum); - JITDUMP("Marking V%02u (0x%02x) as definitely stack-pointing\n", lclNum, bvIndex); + MarkIndexAsDefinitelyStackPointing(bvIndex); +} + +//------------------------------------------------------------------------------ +// MarIndexAsDefinitelyStackPointing : Mark resource as definitely pointing +// to a stack-allocated object. +// +// +// Arguments: +// index - bv index for the resource +// +void ObjectAllocator::MarkIndexAsDefinitelyStackPointing(unsigned int bvIndex) +{ BitVecOps::AddElemD(&m_bitVecTraits, m_DefinitelyStackPointingPointers, bvIndex); } @@ -323,11 +327,24 @@ void ObjectAllocator::MarkLclVarAsDefinitelyStackPointing(unsigned int lclNum) // Arguments: // sourceLclNum - Local variable number of the edge source // targetLclNum - Local variable number of the edge target - +// void ObjectAllocator::AddConnGraphEdge(unsigned int sourceLclNum, unsigned int targetLclNum) { const unsigned sourceBvIndex = LocalToIndex(sourceLclNum); const unsigned targetBvIndex = LocalToIndex(targetLclNum); + AddConnGraphEdgeIndex(sourceBvIndex, targetBvIndex); +} + +//------------------------------------------------------------------------------ +// AddConnGraphEdgeIndex : Record that the source resource may point to the same set of objects +// as the set pointed to by target resource +// +// Arguments: +// sourceBvIndex - index of the edge source +// targetBvIndex - index of the edge target +// +void ObjectAllocator::AddConnGraphEdgeIndex(unsigned int sourceBvIndex, unsigned int targetBvIndex) +{ BitVecOps::AddElemD(&m_bitVecTraits, m_ConnGraphAdjacencyMatrix[sourceBvIndex], targetBvIndex); } @@ -346,11 +363,7 @@ void ObjectAllocator::PrepareAnalysis() // // If conditional escape analysis is enabled, we reserve the range [L...L+M-1] // for locals allocated during the conditional escape analysis expansions, - // where M is the maximum number of pseudo-vars. - // - // We reserve the range [L+M ... L+2M-1] for pseudo locals themselves. - // - // We reserve the singleton [L+2M] for the "unknown source" local + // where M is the maximum number of pseudos. // // In "bv" space // @@ -360,9 +373,9 @@ void ObjectAllocator::PrepareAnalysis() // // If conditional escape analysis is enabled, we reserve the range [N...N+M-1] // for locals allocated during the conditional escape analysis expansions, - // where N is the maximum number of pseudo-vars. + // where N is the maximum number of pseudos. // - // We reserve the range [N+M ... N+2M-1] for pseudo locals themselves. + // We reserve the range [N+M ... N+2M-1] for pseudos. // // We reserve the singleton [N+2M] for the "unknown source" local // @@ -427,8 +440,8 @@ void ObjectAllocator::PrepareAnalysis() if (inRange) { - JITDUMP("Enabling conditional escape analysis [%u pseudo-vars]\n", enumeratorLocalCount); - m_maxPseudoLocals = enumeratorLocalCount; + JITDUMP("Enabling conditional escape analysis [%u pseudos]\n", enumeratorLocalCount); + m_maxPseudos = enumeratorLocalCount; } else { @@ -437,7 +450,7 @@ void ObjectAllocator::PrepareAnalysis() } else { - JITDUMP("Not enabling conditional escape analysis [%u pseudo-vars]: %s\n", enumeratorLocalCount, + JITDUMP("Not enabling conditional escape analysis [%u pseudos]: %s\n", enumeratorLocalCount, enableConditionalEscape ? "OSR" : "disabled by config"); } } @@ -460,16 +473,15 @@ void ObjectAllocator::PrepareAnalysis() // When we clone to prevent conditional escape, we'll also create a new local // var that we will track. So we need to leave room for these vars. There can - // be as many of these as there are pseudo locals. + // be as many of these as there are pseudos. // - m_firstPseudoLocalNum = localCount + m_maxPseudoLocals; // L + M, per above - m_firstPseudoLocalIndex = bvNext + m_maxPseudoLocals; // N, per above - bvNext += 2 * m_maxPseudoLocals; + const unsigned maxTrackedLclNum = localCount + m_maxPseudos; + m_firstPseudoIndex = bvNext + m_maxPseudos; // N, per above + bvNext += 2 * m_maxPseudos; - // A local representing an unknown source of values + // A bv index for an unknown source of values // - m_unknownSourceLocalNum = m_firstPseudoLocalNum + m_maxPseudoLocals; - m_unknownSourceIndex = bvNext; + m_unknownSourceIndex = bvNext; bvNext++; // Now set up the BV traits. @@ -480,9 +492,9 @@ void ObjectAllocator::PrepareAnalysis() // Create the reverse mapping from bvIndex to local var index // (leave room for locals we may allocate) // - if (comp->lvaTrackedToVarNumSize < m_firstPseudoLocalNum) + if (comp->lvaTrackedToVarNumSize < maxTrackedLclNum) { - comp->lvaTrackedToVarNumSize = m_firstPseudoLocalNum; + comp->lvaTrackedToVarNumSize = maxTrackedLclNum; comp->lvaTrackedToVarNum = new (comp->getAllocator(CMK_LvaTable)) unsigned[comp->lvaTrackedToVarNumSize]; } @@ -502,21 +514,17 @@ void ObjectAllocator::PrepareAnalysis() if (m_nextLocalIndex > 0) { JITDUMP("\nLocal var range [%02u...%02u]\n", 0, localCount - 1); - if (m_maxPseudoLocals > 0) + if (m_maxPseudos > 0) { - JITDUMP("Enumerator var range [%02u...%02u]\n", localCount, localCount + m_maxPseudoLocals - 1); - JITDUMP("Pseudo var range [%02u...%02u]\n", m_firstPseudoLocalNum, - m_firstPseudoLocalNum + m_maxPseudoLocals - 1); + JITDUMP("Enumerator var range [%02u...%02u]\n", localCount, localCount + m_maxPseudos - 1); } - JITDUMP("Unknown var range [%02u...%02u]\n", m_unknownSourceLocalNum, m_unknownSourceLocalNum); JITDUMP("\nLocal var bv range [%02u...%02u]\n", 0, m_nextLocalIndex - 1); - if (m_maxPseudoLocals > 0) + if (m_maxPseudos > 0) { - JITDUMP("Enumerator var bv range [%02u...%02u]\n", m_nextLocalIndex, - m_nextLocalIndex + m_maxPseudoLocals - 1); - JITDUMP("Pseudo var bv range [%02u...%02u]\n", m_nextLocalIndex + m_maxPseudoLocals, - m_nextLocalIndex + 2 * m_maxPseudoLocals - 1); + JITDUMP("Enumerator var bv range [%02u...%02u]\n", m_nextLocalIndex, m_nextLocalIndex + m_maxPseudos - 1); + JITDUMP("Pseudo var bv range [%02u...%02u]\n", m_nextLocalIndex + m_maxPseudos, + m_nextLocalIndex + 2 * m_maxPseudos - 1); } JITDUMP("Unknown var bv range [%02u...%02u]\n", m_unknownSourceIndex, m_unknownSourceIndex); } @@ -540,13 +548,18 @@ void ObjectAllocator::DoAnalysis() // If we are doing conditional escape analysis, we also need to compute dominance. // - if (CanHavePseudoLocals()) + if (CanHavePseudos()) { assert(comp->m_dfsTree != nullptr); assert(comp->m_domTree == nullptr); comp->m_domTree = FlowGraphDominatorTree::Build(comp->m_dfsTree); } + for (unsigned int i = 0; i < m_bvCount; i++) + { + m_ConnGraphAdjacencyMatrix[i] = BitVecOps::MakeEmpty(&m_bitVecTraits); + } + MarkEscapingVarsAndBuildConnGraph(); ComputeEscapingNodes(&m_bitVecTraits, m_EscapingPointers); } @@ -674,7 +687,8 @@ void ObjectAllocator::MarkEscapingVarsAndBuildConnGraph() // Add a connection to the unknown source. // JITDUMP("V%02u value unknown at [%06u]\n", lclNum, m_compiler->dspTreeID(tree)); - m_allocator->AddConnGraphEdge(lclNum, m_allocator->m_unknownSourceLocalNum); + m_allocator->AddConnGraphEdgeIndex(m_allocator->LocalToIndex(lclNum), + m_allocator->m_unknownSourceIndex); } } } @@ -691,21 +705,20 @@ void ObjectAllocator::MarkEscapingVarsAndBuildConnGraph() continue; } - LclVarDsc* const lclDsc = comp->lvaGetDesc(lclNum); - const unsigned bvIndex = LocalToIndex(lclNum); - m_ConnGraphAdjacencyMatrix[bvIndex] = BitVecOps::MakeEmpty(&m_bitVecTraits); + LclVarDsc* const lclDsc = comp->lvaGetDesc(lclNum); + const unsigned bvIndex = LocalToIndex(lclNum); if (lclDsc->IsAddressExposed()) { JITDUMP(" V%02u is address exposed\n", lclNum); - MarkLclVarAsEscaping(lclNum); + MarkIndexAsEscaping(bvIndex); continue; } if (lclNum == comp->info.compRetBuffArg) { JITDUMP(" V%02u is retbuff\n", lclNum); - MarkLclVarAsEscaping(lclNum); + MarkIndexAsEscaping(bvIndex); continue; } @@ -716,7 +729,7 @@ void ObjectAllocator::MarkEscapingVarsAndBuildConnGraph() if (lclDsc->lvIsParam && lclDsc->lvIsImplicitByRef) { JITDUMP(" V%02u is an implicit byref param\n", lclNum); - MarkLclVarAsEscaping(lclNum); + MarkIndexAsEscaping(bvIndex); continue; } #endif @@ -726,17 +739,11 @@ void ObjectAllocator::MarkEscapingVarsAndBuildConnGraph() // if (lclDsc->lvIsParam || lclDsc->lvIsOSRLocal) { - AddConnGraphEdge(lclNum, m_unknownSourceLocalNum); + AddConnGraphEdgeIndex(bvIndex, m_unknownSourceIndex); } } - for (unsigned int p = 0; p < m_maxPseudoLocals; p++) - { - m_ConnGraphAdjacencyMatrix[p + m_firstPseudoLocalIndex] = BitVecOps::MakeEmpty(&m_bitVecTraits); - } - - m_ConnGraphAdjacencyMatrix[m_unknownSourceIndex] = BitVecOps::MakeEmpty(&m_bitVecTraits); - MarkLclVarAsEscaping(m_unknownSourceLocalNum); + MarkIndexAsEscaping(m_unknownSourceIndex); // We should have computed the DFS tree already. // @@ -819,7 +826,7 @@ void ObjectAllocator::ComputeEscapingNodes(BitVecTraits* bitVecTraits, BitVec& e computeClosure(); - if (m_numPseudoLocals > 0) + if (m_numPseudos > 0) { bool newEscapes = AnalyzeIfCloningCanPreventEscape(bitVecTraits, escapingNodes, escapingNodesToProcess); if (newEscapes) @@ -851,34 +858,27 @@ void ObjectAllocator::ComputeStackObjectPointers(BitVecTraits* bitVecTraits) { JITDUMP("\n---- computing stack pointing locals, pass %u\n", pass++); changed = false; - for (unsigned int lclNum = 0; lclNum < comp->lvaCount; ++lclNum) + for (unsigned int index = 0; index < m_bvCount; index++) { - if (!IsTrackedLocal(lclNum)) - { - continue; - } - - const unsigned lclIndex = LocalToIndex(lclNum); - - if (!MayLclVarPointToStack(lclNum) && + if (!MayIndexPointToStack(index) && !BitVecOps::IsEmptyIntersection(bitVecTraits, m_PossiblyStackPointingPointers, - m_ConnGraphAdjacencyMatrix[lclIndex])) + m_ConnGraphAdjacencyMatrix[index])) { // We discovered a new pointer that may point to the stack. - JITDUMPEXEC(DumpIndex(lclIndex)); + JITDUMPEXEC(DumpIndex(index)); JITDUMP(" may point to the stack\n"); - MarkLclVarAsPossiblyStackPointing(lclNum); + MarkIndexAsPossiblyStackPointing(index); changed = true; } - if (!BitVecOps::IsMember(bitVecTraits, possiblyHeapPointingPointers, lclIndex) && + if (!BitVecOps::IsMember(bitVecTraits, possiblyHeapPointingPointers, index) && !BitVecOps::IsEmptyIntersection(bitVecTraits, possiblyHeapPointingPointers, - m_ConnGraphAdjacencyMatrix[lclIndex])) + m_ConnGraphAdjacencyMatrix[index])) { // We discovered a new pointer that may point to the heap. - JITDUMPEXEC(DumpIndex(lclIndex)); + JITDUMPEXEC(DumpIndex(index)); JITDUMP(" may point to the heap\n"); - BitVecOps::AddElemD(bitVecTraits, possiblyHeapPointingPointers, lclIndex); + BitVecOps::AddElemD(bitVecTraits, possiblyHeapPointingPointers, index); changed = true; } } @@ -902,10 +902,10 @@ void ObjectAllocator::ComputeStackObjectPointers(BitVecTraits* bitVecTraits) printf("Definitely stack-pointing locals:"); { BitVecOps::Iter iter(bitVecTraits, m_DefinitelyStackPointingPointers); - unsigned lclIndex = 0; - while (iter.NextElem(&lclIndex)) + unsigned index = 0; + while (iter.NextElem(&index)) { - DumpIndex(lclIndex); + DumpIndex(index); } printf("\n"); } @@ -913,12 +913,12 @@ void ObjectAllocator::ComputeStackObjectPointers(BitVecTraits* bitVecTraits) printf("Possibly stack-pointing locals:"); { BitVecOps::Iter iter(bitVecTraits, m_PossiblyStackPointingPointers); - unsigned lclIndex = 0; - while (iter.NextElem(&lclIndex)) + unsigned index = 0; + while (iter.NextElem(&index)) { - if (!BitVecOps::IsMember(bitVecTraits, m_DefinitelyStackPointingPointers, lclIndex)) + if (!BitVecOps::IsMember(bitVecTraits, m_DefinitelyStackPointingPointers, index)) { - DumpIndex(lclIndex); + DumpIndex(index); } } printf("\n"); @@ -1290,11 +1290,11 @@ bool ObjectAllocator::MorphAllocObjNodes() // and the enumeratorLocal we already allocated. This is needed because we do early rewriting // in the conditional clone. // - unsigned pseudoLocal = BAD_VAR_NUM; - if (m_EnumeratorLocalToPseudoLocalMap.TryGetValue(lclNum, &pseudoLocal)) + unsigned pseudoIndex = BAD_VAR_NUM; + if (m_EnumeratorLocalToPseudoIndexMap.TryGetValue(lclNum, &pseudoIndex)) { CloneInfo* info = nullptr; - if (m_CloneMap.Lookup(pseudoLocal, &info)) + if (m_CloneMap.Lookup(pseudoIndex, &info)) { if (info->m_willClone) { @@ -1328,7 +1328,7 @@ bool ObjectAllocator::MorphAllocObjNodes() if (IsTrackedLocal(lclNum)) { - AddConnGraphEdge(lclNum, m_unknownSourceLocalNum); + AddConnGraphEdgeIndex(LocalToIndex(lclNum), m_unknownSourceIndex); } } } @@ -1886,7 +1886,7 @@ bool ObjectAllocator::CanLclVarEscapeViaParentStack(ArrayStack* parent // // In particular it might be tempting to look for references in uncatchable BBJ_THROWs or similar // and enable a kind of "partial escape analysis" where we copy from stack to heap just before the - // point of escape. We would have to add pseudo-locals for this like we do for GDV, but we wouldn't + // point of escape. We would have to add pseudos for this like we do for GDV, but we wouldn't // necessarily need to do the predicate analysis or cloning. // if (isEnumeratorLocal) @@ -2470,14 +2470,14 @@ void ObjectAllocator::RewriteUses() // // Notes: // During our analysis we have may have noted conditionally escaping objects -// and var references and connected them to a pseduolocal, along with information +// and var references and connected them to a pseduo, along with information // about how we could clone blocks to ensure that the object could be stack allocated. // // The current assumption is that these nodes do not escape, but to ensure // that we must be able to clone the code and remove the potential for escape // -// So, we verify for each case that we can clone; if not, mark we the pseudolocal -// as escaping. If any pseudo local now escapes, we return true so that the main +// So, we verify for each case that we can clone; if not, mark we the Pseudo +// as escaping. If any pseudo now escapes, we return true so that the main // analysis can update its closure. // // We may choose not to clone a candiate for several reasons: @@ -2491,38 +2491,41 @@ bool ObjectAllocator::AnalyzeIfCloningCanPreventEscape(BitVecTraits* bitVecTrait { bool newEscapes = false; - for (unsigned p = 0; p < m_numPseudoLocals; p++) + for (unsigned p = 0; p < m_numPseudos; p++) { - unsigned const pseudoLocal = p + m_firstPseudoLocalNum; + unsigned const pseudoIndex = p + m_firstPseudoIndex; bool canClone = true; CloneInfo* info = nullptr; - const bool hasInfo = m_CloneMap.Lookup(pseudoLocal, &info); + const bool hasInfo = m_CloneMap.Lookup(pseudoIndex, &info); if (!hasInfo) { - // We never found any conditional allocation attached to this pseudoLocal. + // We never found any conditional allocation attached to this pseudoIndex. // - JITDUMP(" P%02u has no guard info\n", pseudoLocal); + JITDUMPEXEC(DumpIndex(pseudoIndex)); + JITDUMP(" has no guard info\n"); canClone = false; break; } - // See what locals were "assigned" to the pseudo local. + // See what locals were "assigned" to the pseudo. // - BitVec pseudoLocalAdjacencies = m_ConnGraphAdjacencyMatrix[LocalToIndex(pseudoLocal)]; + BitVec PseudoAdjacencies = m_ConnGraphAdjacencyMatrix[pseudoIndex]; // If we found an allocation but didn't find any conditionally escaping uses, then cloning is of no use // - if (BitVecOps::IsEmpty(bitVecTraits, pseudoLocalAdjacencies)) + if (BitVecOps::IsEmpty(bitVecTraits, PseudoAdjacencies)) { - JITDUMP(" No conditionally escaping uses under P%02u, so no reason to clone\n", pseudoLocal); + JITDUMP(" No conditionally escaping uses under"); + JITDUMPEXEC(DumpIndex(pseudoIndex)); + JITDUMP(", so no reason to clone\n"); canClone = false; break; } // Check if each conditionally escaping local escapes on its own; if so cloning is of no use // - BitVecOps::Iter iterator(bitVecTraits, pseudoLocalAdjacencies); + BitVecOps::Iter iterator(bitVecTraits, PseudoAdjacencies); unsigned lclNumIndex = BAD_VAR_NUM; while (canClone && iterator.NextElem(&lclNumIndex)) { @@ -2531,7 +2534,10 @@ bool ObjectAllocator::AnalyzeIfCloningCanPreventEscape(BitVecTraits* bitVecTrait // The enumerator var or a related var had escaping uses somewhere in the method, // not under a failing GDV or any GDV. // - JITDUMP(" V%02u escapes independently of P%02u\n", IndexToLocal(lclNumIndex), pseudoLocal); + JITDUMPEXEC(DumpIndex(lclNumIndex)); + JITDUMP(" escapes independently of", IndexToLocal(lclNumIndex)); + JITDUMPEXEC(DumpIndex(pseudoIndex)); + JITDUMP("\n"); canClone = false; break; } @@ -2545,7 +2551,12 @@ bool ObjectAllocator::AnalyzeIfCloningCanPreventEscape(BitVecTraits* bitVecTrait { if (BitVecOps::IsMember(bitVecTraits, escapingNodes, LocalToIndex(v))) { - JITDUMP(" alloc temp V%02u escapes independently of P%02u\n", v, pseudoLocal) + JITDUMP(" alloc temp"); + JITDUMPEXEC(DumpIndex(v)); + JITDUMP(" escapes independently of", IndexToLocal(lclNumIndex)); + JITDUMPEXEC(DumpIndex(pseudoIndex)); + JITDUMP("\n"); + canClone = false; break; } @@ -2557,7 +2568,8 @@ bool ObjectAllocator::AnalyzeIfCloningCanPreventEscape(BitVecTraits* bitVecTrait // We may be able to clone and specialize the enumerator uses to ensure // that the allocated enumerator does not escape. // - JITDUMP(" P%02u is guarding the escape of V%02u\n", pseudoLocal, info->m_local); + JITDUMPEXEC(DumpIndex(pseudoIndex)); + JITDUMP(" is guarding the escape of V%02u\n", info->m_local); if (info->m_allocTemps != nullptr) { JITDUMP(" along with "); @@ -2598,15 +2610,20 @@ bool ObjectAllocator::AnalyzeIfCloningCanPreventEscape(BitVecTraits* bitVecTrait // if (canClone) { - JITDUMP("\n*** Can prevent escape under P%02u via cloning ***\n", pseudoLocal); + JITDUMP("\n*** Can prevent escape under"); + JITDUMPEXEC(DumpIndex(pseudoIndex)); + JITDUMP(" via cloning ***\n"); + info->m_willClone = true; m_regionsToClone++; } else { - JITDUMP(" not optimizing, so will mark P%02u as escaping\n", pseudoLocal); - MarkLclVarAsEscaping(pseudoLocal); - BitVecOps::AddElemD(bitVecTraits, escapingNodesToProcess, LocalToIndex(pseudoLocal)); + JITDUMP(" not optimizing, so will mark"); + JITDUMPEXEC(DumpIndex(pseudoIndex)); + JITDUMP(" as escaping\n"); + MarkIndexAsEscaping(pseudoIndex); + BitVecOps::AddElemD(bitVecTraits, escapingNodesToProcess, pseudoIndex); newEscapes = true; } } @@ -2615,18 +2632,22 @@ bool ObjectAllocator::AnalyzeIfCloningCanPreventEscape(BitVecTraits* bitVecTrait } //------------------------------------------------------------------------------ -// NewPseudoLocal: return index of a new pseudo local. +// NewPseudoIndex: return index of a new pseudo. // // Returns: // index to use, or BAD_VAR_NUM if no more indices are available. // -unsigned ObjectAllocator::NewPseudoLocal() +unsigned ObjectAllocator::NewPseudoIndex() { unsigned result = BAD_VAR_NUM; - if (m_numPseudoLocals < m_maxPseudoLocals) + if (m_numPseudos >= m_maxPseudos) + { + assert(!"unexpected number of pseudos"); + } + else { - result = m_firstPseudoLocalNum + m_numPseudoLocals; - m_numPseudoLocals++; + result = m_firstPseudoIndex + m_numPseudos; + m_numPseudos++; } return result; } @@ -2835,12 +2856,12 @@ GenTree* ObjectAllocator::IsGuard(BasicBlock* block, GuardInfo* info) // bool ObjectAllocator::CheckForGuardedUse(BasicBlock* block, GenTree* tree, unsigned lclNum) { - // Find pseudo local... + // Find pseudo... // - unsigned pseudoLocal = BAD_VAR_NUM; - if (!m_EnumeratorLocalToPseudoLocalMap.TryGetValue(lclNum, &pseudoLocal)) + unsigned pseudoIndex = BAD_VAR_NUM; + if (!m_EnumeratorLocalToPseudoIndexMap.TryGetValue(lclNum, &pseudoIndex)) { - JITDUMP("... no pseudo local?\n"); + JITDUMP("... no pseudo?\n"); return false; } @@ -2853,10 +2874,10 @@ bool ObjectAllocator::CheckForGuardedUse(BasicBlock* block, GenTree* tree, unsig return false; } - // Find the GDV guard for the pseudo-local + // Find the GDV guard for the pseudo // CloneInfo* pseudoGuardInfo; - if (!m_CloneMap.Lookup(pseudoLocal, &pseudoGuardInfo)) + if (!m_CloneMap.Lookup(pseudoIndex, &pseudoGuardInfo)) { JITDUMP("... under non-gdv guard?\n"); return false; @@ -2866,14 +2887,16 @@ bool ObjectAllocator::CheckForGuardedUse(BasicBlock* block, GenTree* tree, unsig // if ((info.m_local == lclNum) && (pseudoGuardInfo->m_local == lclNum) && (info.m_type == pseudoGuardInfo->m_type)) { - // If so, track this as an assignment pseudoLocal = ... + // If so, track this as an assignment pseudoIndex = ... // // Later if we don't clone and split off the failing GDV paths, - // we will mark pseudoLocal as escaped, and that will lead + // we will mark pseudoIndex as escaped, and that will lead // to lclNum escaping as well. // - JITDUMP("... under GDV; tracking via pseudo-local P%02u\n", pseudoLocal); - AddConnGraphEdge(pseudoLocal, lclNum); + JITDUMP("... under GDV; tracking via pseudo index"); + JITDUMPEXEC(DumpIndex(pseudoIndex)); + JITDUMP("\n") + AddConnGraphEdgeIndex(pseudoIndex, LocalToIndex(lclNum)); return true; } @@ -2904,7 +2927,7 @@ void ObjectAllocator::CheckForGuardedAllocationOrCopy(BasicBlock* block, GenTree* const tree = *use; assert(tree->OperIsLocalStore()); - if (!CanHavePseudoLocals()) + if (!CanHavePseudos()) { // We didn't flag any allocations of interest during importation, // so there is nothing to do here. @@ -2951,11 +2974,11 @@ void ObjectAllocator::CheckForGuardedAllocationOrCopy(BasicBlock* block, if (CanAllocateLclVarOnStack(enumeratorLocal, clsHnd, OAT_NEWOBJ, length, &size, &reason, /* preliminaryCheck */ true)) { - // We are going to conditionally track accesses to the enumerator local via a pseudo local. + // We are going to conditionally track accesses to the enumerator local via a pseudo. // - const unsigned pseudoLocal = NewPseudoLocal(); - assert(pseudoLocal != BAD_VAR_NUM); - bool added = m_EnumeratorLocalToPseudoLocalMap.AddOrUpdate(enumeratorLocal, pseudoLocal); + const unsigned pseudoIndex = NewPseudoIndex(); + assert(pseudoIndex != BAD_VAR_NUM); + bool added = m_EnumeratorLocalToPseudoIndexMap.AddOrUpdate(enumeratorLocal, pseudoIndex); if (!added) { @@ -2977,16 +3000,18 @@ void ObjectAllocator::CheckForGuardedAllocationOrCopy(BasicBlock* block, CloneInfo* info = new (alloc) CloneInfo(); info->m_local = enumeratorLocal; info->m_type = clsHnd; - info->m_pseudoLocal = pseudoLocal; + info->m_pseudoIndex = pseudoIndex; info->m_appearanceMap = new (alloc) EnumeratorVarMap(alloc); info->m_allocBlock = block; info->m_allocStmt = stmt; info->m_allocTree = data; info->m_domBlock = controllingGDV.m_block; - m_CloneMap.Set(pseudoLocal, info); + m_CloneMap.Set(pseudoIndex, info); - JITDUMP("Enumerator allocation [%06u]: will track accesses to V%02u guarded by type %s via P%02u\n", - comp->dspTreeID(data), enumeratorLocal, comp->eeGetClassName(clsHnd), pseudoLocal); + JITDUMP("Enumerator allocation [%06u]: will track accesses to V%02u guarded by type %s via", + comp->dspTreeID(data), enumeratorLocal, comp->eeGetClassName(clsHnd)); + JITDUMPEXEC(DumpIndex(pseudoIndex)); + JITDUMP("\n"); // If this is not a direct assignment to the enumerator var we also need to // track the temps that will appear in between. Later we will rewrite these @@ -3056,16 +3081,16 @@ void ObjectAllocator::CheckForGuardedAllocationOrCopy(BasicBlock* block, // bool ObjectAllocator::CheckForEnumeratorUse(unsigned lclNum, unsigned dstLclNum) { - unsigned pseudoLocal = BAD_VAR_NUM; + unsigned pseudoIndex = BAD_VAR_NUM; - if (m_EnumeratorLocalToPseudoLocalMap.TryGetValue(dstLclNum, &pseudoLocal)) + if (m_EnumeratorLocalToPseudoIndexMap.TryGetValue(dstLclNum, &pseudoIndex)) { // We already knew dstLclNum was a potential copy // return true; } - if (!m_EnumeratorLocalToPseudoLocalMap.TryGetValue(lclNum, &pseudoLocal)) + if (!m_EnumeratorLocalToPseudoIndexMap.TryGetValue(lclNum, &pseudoIndex)) { // lclNum is not a potential source // @@ -3073,7 +3098,7 @@ bool ObjectAllocator::CheckForEnumeratorUse(unsigned lclNum, unsigned dstLclNum) } CloneInfo* info = nullptr; - if (!m_CloneMap.Lookup(pseudoLocal, &info)) + if (!m_CloneMap.Lookup(pseudoIndex, &info)) { // We aren't interested in locals under this guard // @@ -3082,11 +3107,13 @@ bool ObjectAllocator::CheckForEnumeratorUse(unsigned lclNum, unsigned dstLclNum) // lclNum is an interesting enumerator var, so now so is dstLclNum. // - const bool added = m_EnumeratorLocalToPseudoLocalMap.AddOrUpdate(dstLclNum, pseudoLocal); + const bool added = m_EnumeratorLocalToPseudoIndexMap.AddOrUpdate(dstLclNum, pseudoIndex); assert(added); - JITDUMP("Enumerator allocation: will also track accesses to V%02u via P%02u\n", dstLclNum, pseudoLocal); + JITDUMP("Enumerator allocation: will also track accesses to V%02u via", dstLclNum); + JITDUMPEXEC(DumpIndex(pseudoIndex)); + JITDUMP("\n"); if (info->m_allocTemps == nullptr) { @@ -3110,14 +3137,14 @@ bool ObjectAllocator::CheckForEnumeratorUse(unsigned lclNum, unsigned dstLclNum) // void ObjectAllocator::RecordAppearance(unsigned lclNum, BasicBlock* block, Statement* stmt, GenTree** use) { - unsigned pseudoLocal = BAD_VAR_NUM; - if (!m_EnumeratorLocalToPseudoLocalMap.TryGetValue(lclNum, &pseudoLocal)) + unsigned Pseudo = BAD_VAR_NUM; + if (!m_EnumeratorLocalToPseudoIndexMap.TryGetValue(lclNum, &Pseudo)) { return; } CloneInfo* info; - if (!m_CloneMap.Lookup(pseudoLocal, &info)) + if (!m_CloneMap.Lookup(Pseudo, &info)) { return; } @@ -3198,8 +3225,11 @@ bool ObjectAllocator::CloneOverlaps(CloneInfo* info) continue; } - JITDUMP("Cloned blocks for P%02u overlap with those for P%02u; unable to clone\n", info->m_pseudoLocal, - c->m_pseudoLocal); + JITDUMP("Cloned blocks for"); + JITDUMPEXEC(DumpIndex(info->m_pseudoIndex)); + JITDUMP(" overlap with those for"); + JITDUMPEXEC(DumpIndex(c->m_pseudoIndex)); + JITDUMP(" unable to clone\n"); overlaps = true; break; @@ -3235,7 +3265,9 @@ bool ObjectAllocator::ShouldClone(CloneInfo* info) unsigned blockSize = 0; if (block->ComplexityExceeds(comp, slack, &blockSize)) { - JITDUMP("Rejecting P%02u cloning: exceeds size limit %u\n", info->m_pseudoLocal, sizeLimit); + JITDUMP("Rejecting"); + JITDUMPEXEC(DumpIndex(info->m_pseudoIndex)); + JITDUMP(" cloning: exceeds size limit %u\n", sizeLimit); return false; } size += blockSize; @@ -3243,7 +3275,9 @@ bool ObjectAllocator::ShouldClone(CloneInfo* info) // TODO: some kind of profile check... // - JITDUMP("Accepting P%02u cloning: size %u does not exceed size limit %u\n", info->m_pseudoLocal, size, sizeLimit); + JITDUMP("Accepting"); + JITDUMPEXEC(DumpIndex(info->m_pseudoIndex)); + JITDUMP(" cloning: size %u does not exceed size limit %u\n", size, sizeLimit); return true; } @@ -3905,8 +3939,8 @@ void ObjectAllocator::CloneAndSpecialize(CloneInfo* info) comp->lvaTrackedToVarNum[newEnumeratorDsc->lvVarIndex] = newEnumeratorLocal; m_ConnGraphAdjacencyMatrix[newEnumeratorDsc->lvVarIndex] = BitVecOps::MakeEmpty(&m_bitVecTraits); m_nextLocalIndex++; - assert(m_maxPseudoLocals > 0); - assert(newEnumeratorDsc->lvVarIndex < m_firstPseudoLocalIndex); + assert(m_maxPseudos > 0); + assert(newEnumeratorDsc->lvVarIndex < m_firstPseudoIndex); JITDUMP("Tracking V%02u via 0x%02x\n", newEnumeratorLocal, newEnumeratorDsc->lvVarIndex); diff --git a/src/runtime/src/coreclr/jit/objectalloc.h b/src/runtime/src/coreclr/jit/objectalloc.h index b3d07d7eb06..599b556db75 100644 --- a/src/runtime/src/coreclr/jit/objectalloc.h +++ b/src/runtime/src/coreclr/jit/objectalloc.h @@ -75,8 +75,8 @@ struct CloneInfo : public GuardInfo m_blocks = BitVecOps::UninitVal(); } - // Pseudo-local tracking conditinal escapes - unsigned m_pseudoLocal = BAD_VAR_NUM; + // Pseudo-local tracking conditional escapes + unsigned m_pseudoIndex = BAD_VAR_NUM; // Local allocated for the address of the enumerator unsigned m_enumeratorLocal = BAD_VAR_NUM; @@ -128,7 +128,6 @@ class ObjectAllocator final : public Phase bool m_isR2R; unsigned m_bvCount; BitVecTraits m_bitVecTraits; - unsigned m_unknownSourceLocalNum; unsigned m_unknownSourceIndex; BitVec m_EscapingPointers; // We keep the set of possibly-stack-pointing pointers as a superset of the set of @@ -140,13 +139,12 @@ class ObjectAllocator final : public Phase unsigned int m_StackAllocMaxSize; // Info for conditionally-escaping locals - LocalToLocalMap m_EnumeratorLocalToPseudoLocalMap; + LocalToLocalMap m_EnumeratorLocalToPseudoIndexMap; CloneMap m_CloneMap; unsigned m_nextLocalIndex; - unsigned m_firstPseudoLocalNum; - unsigned m_firstPseudoLocalIndex; - unsigned m_numPseudoLocals; - unsigned m_maxPseudoLocals; + unsigned m_firstPseudoIndex; + unsigned m_numPseudos; + unsigned m_maxPseudos; unsigned m_regionsToClone; // Struct fields @@ -172,19 +170,24 @@ class ObjectAllocator final : public Phase private: bool IsTrackedType(var_types type); bool IsTrackedLocal(unsigned lclNum); - bool HasIndex(unsigned lclNum); unsigned LocalToIndex(unsigned lclNum); unsigned IndexToLocal(unsigned bvIndex); bool CanLclVarEscape(unsigned int lclNum); void MarkLclVarAsPossiblyStackPointing(unsigned int lclNum); + void MarkIndexAsPossiblyStackPointing(unsigned int index); void MarkLclVarAsDefinitelyStackPointing(unsigned int lclNum); + void MarkIndexAsDefinitelyStackPointing(unsigned int index); bool MayLclVarPointToStack(unsigned int lclNum); bool DoesLclVarPointToStack(unsigned int lclNum); + bool MayIndexPointToStack(unsigned int index); + bool DoesIndexPointToStack(unsigned int index); void PrepareAnalysis(); void DoAnalysis(); void MarkLclVarAsEscaping(unsigned int lclNum); + void MarkIndexAsEscaping(unsigned int lclNum); void MarkEscapingVarsAndBuildConnGraph(); void AddConnGraphEdge(unsigned int sourceLclNum, unsigned int targetLclNum); + void AddConnGraphEdgeIndex(unsigned int sourceIndex, unsigned int targetIndex); void ComputeEscapingNodes(BitVecTraits* bitVecTraits, BitVec& escapingNodes); void ComputeStackObjectPointers(BitVecTraits* bitVecTraits); bool MorphAllocObjNodes(); @@ -212,11 +215,11 @@ class ObjectAllocator final : public Phase bool CheckForEnumeratorUse(unsigned lclNum, unsigned dstLclNum); bool IsGuarded(BasicBlock* block, GenTree* tree, GuardInfo* info, bool testOutcome); GenTree* IsGuard(BasicBlock* block, GuardInfo* info); - unsigned NewPseudoLocal(); + unsigned NewPseudoIndex(); - bool CanHavePseudoLocals() + bool CanHavePseudos() { - return (m_maxPseudoLocals > 0); + return (m_maxPseudos > 0); } void RecordAppearance(unsigned lclNum, BasicBlock* block, Statement* stmt, GenTree** use); @@ -272,7 +275,7 @@ inline void ObjectAllocator::EnableObjectStackAllocation() inline bool ObjectAllocator::CanLclVarEscape(unsigned int lclNum) { - if (!HasIndex(lclNum)) + if (!IsTrackedLocal(lclNum)) { return true; } @@ -281,6 +284,22 @@ inline bool ObjectAllocator::CanLclVarEscape(unsigned int lclNum) return BitVecOps::IsMember(&m_bitVecTraits, m_EscapingPointers, bvIndex); } +//------------------------------------------------------------------------ +// MayIndexPointToStack: Returns true iff the resource described by index may +// point to a stack-allocated object +// +// Arguments: +// index - bv index +// +// Return Value: +// Returns true if so. +// +inline bool ObjectAllocator::MayIndexPointToStack(unsigned int index) +{ + assert(m_AnalysisDone); + return BitVecOps::IsMember(&m_bitVecTraits, m_PossiblyStackPointingPointers, index); +} + //------------------------------------------------------------------------ // MayLclVarPointToStack: Returns true iff local variable may // point to a stack-allocated object @@ -290,18 +309,33 @@ inline bool ObjectAllocator::CanLclVarEscape(unsigned int lclNum) // // Return Value: // Returns true iff local variable may point to a stack-allocated object - +// inline bool ObjectAllocator::MayLclVarPointToStack(unsigned int lclNum) { assert(m_AnalysisDone); - if (!HasIndex(lclNum)) + if (!IsTrackedLocal(lclNum)) { return false; } - const unsigned bvIndex = LocalToIndex(lclNum); - return BitVecOps::IsMember(&m_bitVecTraits, m_PossiblyStackPointingPointers, bvIndex); + return MayIndexPointToStack(LocalToIndex(lclNum)); +} + +//------------------------------------------------------------------------ +// DoesIndexPointToStack: Returns true iff the resource described by index definitely +// points to a stack-allocated object (or is null) +// +// Arguments: +// index - bv index +// +// Return Value: +// Returns true if so. +// +inline bool ObjectAllocator::DoesIndexPointToStack(unsigned int index) +{ + assert(m_AnalysisDone); + return BitVecOps::IsMember(&m_bitVecTraits, m_DefinitelyStackPointingPointers, index); } //------------------------------------------------------------------------ @@ -314,18 +348,17 @@ inline bool ObjectAllocator::MayLclVarPointToStack(unsigned int lclNum) // Return Value: // Returns true iff local variable definitely points to a stack-allocated object // (or is null) - +// inline bool ObjectAllocator::DoesLclVarPointToStack(unsigned int lclNum) { assert(m_AnalysisDone); - if (!HasIndex(lclNum)) + if (!IsTrackedLocal(lclNum)) { return false; } - const unsigned bvIndex = LocalToIndex(lclNum); - return BitVecOps::IsMember(&m_bitVecTraits, m_DefinitelyStackPointingPointers, bvIndex); + return DoesIndexPointToStack(LocalToIndex(lclNum)); } //=============================================================================== diff --git a/src/runtime/src/coreclr/jit/simd.h b/src/runtime/src/coreclr/jit/simd.h index 2f7610b7e61..d0450fa91ca 100644 --- a/src/runtime/src/coreclr/jit/simd.h +++ b/src/runtime/src/coreclr/jit/simd.h @@ -330,18 +330,26 @@ struct simdmask_t return !(*this == other); } - static simdmask_t AllBitsSet() + static simdmask_t AllBitsSet(unsigned elementCount) { + assert((elementCount >= 1) && (elementCount <= 64)); simdmask_t result; - result.u64[0] = 0xFFFFFFFFFFFFFFFF; + if (elementCount == 64) + { + result.u64[0] = 0xFFFFFFFFFFFFFFFF; + } + else + { + result.u64[0] = (1ULL << elementCount) - 1; + } return result; } bool IsAllBitsSet() const { - return *this == AllBitsSet(); + return *this == AllBitsSet(64); } bool IsZero() const @@ -1412,7 +1420,7 @@ void EvaluateWithElementFloating(var_types simdBaseType, TSimd* result, const TS case TYP_DOUBLE: { - result->f64[arg1] = static_cast(arg2); + result->f64[arg1] = arg2; break; } diff --git a/src/runtime/src/coreclr/jit/valuenum.cpp b/src/runtime/src/coreclr/jit/valuenum.cpp index 153eb524cdb..3a44a5ea758 100644 --- a/src/runtime/src/coreclr/jit/valuenum.cpp +++ b/src/runtime/src/coreclr/jit/valuenum.cpp @@ -2177,7 +2177,7 @@ ValueNum ValueNumStore::VNOneForType(var_types typ) } } -ValueNum ValueNumStore::VNAllBitsForType(var_types typ) +ValueNum ValueNumStore::VNAllBitsForType(var_types typ, unsigned elementCount) { switch (typ) { @@ -2224,7 +2224,7 @@ ValueNum ValueNumStore::VNAllBitsForType(var_types typ) #if defined(FEATURE_MASKED_HW_INTRINSICS) case TYP_MASK: { - return VNForSimdMaskCon(simdmask_t::AllBitsSet()); + return VNForSimdMaskCon(simdmask_t::AllBitsSet(elementCount)); } #endif // FEATURE_MASKED_HW_INTRINSICS #endif // FEATURE_SIMD @@ -5350,7 +5350,7 @@ ValueNum ValueNumStore::EvalUsingMathIdentity(var_types typ, VNFunc func, ValueN } // Handle `x | AllBitsSet == AllBitsSet` and `AllBitsSet | x == AllBitsSet` - if (cnsVN == VNAllBitsForType(typ)) + if (cnsVN == VNAllBitsForType(typ, 1)) { resultVN = cnsVN; break; @@ -5395,7 +5395,7 @@ ValueNum ValueNumStore::EvalUsingMathIdentity(var_types typ, VNFunc func, ValueN } // Handle `x & AllBitsSet == x` and `AllBitsSet & x == x` - if (cnsVN == VNAllBitsForType(typ)) + if (cnsVN == VNAllBitsForType(typ, 1)) { resultVN = opVN; break; @@ -8040,12 +8040,6 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunUnary(GenTreeHWIntrinsic* tree, return VNForLongCon(static_cast(result)); } - case NI_Vector128_AsVector2: - { - simd8_t result = GetConstantSimd16(arg0VN).v64[0]; - return VNForSimd8Con(result); - } - case NI_Vector128_ToVector256: case NI_Vector128_ToVector256Unsafe: { @@ -8100,6 +8094,12 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunUnary(GenTreeHWIntrinsic* tree, } #endif // TARGET_XARCH + case NI_Vector128_AsVector2: + { + simd8_t result = GetConstantSimd16(arg0VN).v64[0]; + return VNForSimd8Con(result); + } + case NI_Vector128_AsVector3: { simd12_t result = {}; @@ -8393,7 +8393,7 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary( } // Handle `x & AllBitsSet == x` and `AllBitsSet & x == x` - ValueNum allBitsVN = VNAllBitsForType(type); + ValueNum allBitsVN = VNAllBitsForType(type, simdSize); if (cnsVN == allBitsVN) { @@ -8482,7 +8482,8 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary( // Handle `x >= 0 == true` for unsigned types. if ((cnsVN == arg1VN) && (cnsVN == VNZeroForType(simdType))) { - return VNAllBitsForType(type); + unsigned elementCount = simdSize / genTypeSize(baseType); + return VNAllBitsForType(type, elementCount); } } else if (varTypeIsFloating(baseType)) @@ -8528,7 +8529,8 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary( // Handle `0 <= x == true` for unsigned types. if ((cnsVN == arg0VN) && (cnsVN == VNZeroForType(simdType))) { - return VNAllBitsForType(type); + unsigned elementCount = simdSize / genTypeSize(baseType); + return VNAllBitsForType(type, elementCount); } } else if (varTypeIsFloating(baseType)) @@ -8598,7 +8600,8 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary( // Handle `(x != NaN) == true` and `(NaN != x) == true` for floating-point types if (VNIsVectorNaN(simdType, baseType, cnsVN)) { - return VNAllBitsForType(type); + unsigned elementCount = simdSize / genTypeSize(baseType); + return VNAllBitsForType(type, elementCount); } } break; @@ -8615,7 +8618,7 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary( } // Handle `x | ~0 == ~0` and `~0 | x== ~0` - ValueNum allBitsVN = VNAllBitsForType(type); + ValueNum allBitsVN = VNAllBitsForType(type, simdSize); if (cnsVN == allBitsVN) { @@ -8849,7 +8852,8 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunBinary( if (varTypeIsIntegral(baseType)) { - return VNAllBitsForType(type); + unsigned elementCount = simdSize / genTypeSize(baseType); + return VNAllBitsForType(type, elementCount); } break; } @@ -9054,6 +9058,7 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunTernary( { var_types type = tree->TypeGet(); var_types baseType = tree->GetSimdBaseType(); + unsigned simdSize = tree->GetSimdSize(); NamedIntrinsic ni = tree->GetHWIntrinsicId(); switch (ni) @@ -9078,7 +9083,7 @@ ValueNum ValueNumStore::EvalHWIntrinsicFunTernary( } // Handle `AllBitsSet ? x : y` - ValueNum allBitsVN = VNAllBitsForType(type); + ValueNum allBitsVN = VNAllBitsForType(type, simdSize); if (arg0VN == allBitsVN) { diff --git a/src/runtime/src/coreclr/jit/valuenum.h b/src/runtime/src/coreclr/jit/valuenum.h index a643789a284..0edf313ed41 100644 --- a/src/runtime/src/coreclr/jit/valuenum.h +++ b/src/runtime/src/coreclr/jit/valuenum.h @@ -690,7 +690,8 @@ class ValueNumStore // Returns the value number for AllBitsSet of the given "typ". // It has an unreached() for a "typ" that has no all bits set value, such as TYP_VOID. - ValueNum VNAllBitsForType(var_types typ); + // elementCount is used for TYP_MASK and indicates how many bits should be set + ValueNum VNAllBitsForType(var_types typ, unsigned elementCount); #ifdef FEATURE_SIMD // Returns the value number broadcast of the given "simdType" and "simdBaseType". diff --git a/src/runtime/src/coreclr/md/inc/mdinternalrw.h b/src/runtime/src/coreclr/md/inc/mdinternalrw.h index 9d3ea31d75a..dd55ac20abb 100644 --- a/src/runtime/src/coreclr/md/inc/mdinternalrw.h +++ b/src/runtime/src/coreclr/md/inc/mdinternalrw.h @@ -73,16 +73,6 @@ class MDInternalRW : public IMDInternalImportENC, public IMDCommon return static_cast(&m_pStgdb->m_MiniMd); } - __checkReturn - STDMETHODIMP SetOptimizeAccessForSpeed(// return hresult - BOOL fOptSpeed) - { - // If there is any optional work we can avoid (for example, because we have - // traded space for speed) this is the place to turn it off or on. - - return S_OK; - } - //***************************************************************************** // return the count of entries of a given kind in a scope // For example, pass in mdtMethodDef will tell you how many MethodDef @@ -782,32 +772,8 @@ class MDInternalRW : public IMDInternalImportENC, public IMDCommon { return (DWORD)m_pStgdb->m_MiniMd.m_Schema.m_minor | ((DWORD)m_pStgdb->m_MiniMd.m_Schema.m_major << 16); - }; - - __checkReturn - STDMETHODIMP SetVerifiedByTrustedSource(// return hresult - BOOL fVerified) - { - m_pStgdb->m_MiniMd.SetVerifiedByTrustedSource(fVerified); - return S_OK; } - STDMETHODIMP GetRvaOffsetData(// S_OK or error - DWORD *pFirstMethodRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in MethodDef table. - DWORD *pMethodDefRecordSize, // [OUT] Size of each record in MethodDef table. - DWORD *pMethodDefCount, // [OUT] Number of records in MethodDef table. - DWORD *pFirstFieldRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in FieldRVA table. - DWORD *pFieldRvaRecordSize, // [OUT] Size of each record in FieldRVA table. - DWORD *pFieldRvaCount) // [OUT] Number of records in FieldRVA table. - { - return m_pStgdb->m_MiniMd.GetRvaOffsetData( - pFirstMethodRvaOffset, - pMethodDefRecordSize, - pMethodDefCount, - pFirstFieldRvaOffset, - pFieldRvaRecordSize, - pFieldRvaCount); - } }; // class MDInternalRW #endif //FEATURE_METADATA_INTERNAL_APIS diff --git a/src/runtime/src/coreclr/md/inc/metamodel.h b/src/runtime/src/coreclr/md/inc/metamodel.h index 00314646ee7..942a4841279 100644 --- a/src/runtime/src/coreclr/md/inc/metamodel.h +++ b/src/runtime/src/coreclr/md/inc/metamodel.h @@ -40,11 +40,6 @@ #define METAMODEL_MAJOR_VER 2 #define METAMODEL_MINOR_VER 0 -// Metadata version number up through Whidbey Beta2 -#define METAMODEL_MAJOR_VER_B1 1 -#define METAMODEL_MINOR_VER_B1 1 - - typedef enum MetadataVersion { MDVersion1 = 0x00000001, @@ -530,23 +525,6 @@ class CMiniMdBase : public IMetaModelCommonRO return m_fVerifiedByTrustedSource && CommonIsRo(); } - void SetVerifiedByTrustedSource(BOOL fVerifiedByTrustedSource) - { - m_fVerifiedByTrustedSource = fVerifiedByTrustedSource; - } - - STDMETHODIMP GetRvaOffsetData(// S_OK or error - DWORD *pFirstMethodRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in MethodDef table. - DWORD *pMethodDefRecordSize, // [OUT] Size of each record in MethodDef table. - DWORD *pMethodDefCount, // [OUT] Number of records in MethodDef table. - DWORD *pFirstFieldRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in FieldRVA table. - DWORD *pFieldRvaRecordSize, // [OUT] Size of each record in FieldRVA table. - DWORD *pFieldRvaCount) // [OUT] Number of records in FieldRVA table. - { - _ASSERTE("Not implemented"); - return E_NOTIMPL; - } - //***************************************************************************** // Some of the tables need coded tokens, not just rids (ie, the column can // refer to more than one other table). Code the tokens into as few bits @@ -1998,9 +1976,8 @@ template class CMiniMdTemplate : public CMiniMdBase BOOL SupportsGenerics() { - // Only 2.0 of the metadata (and 1.1) support generics - return (m_Schema.m_major >= METAMODEL_MAJOR_VER_V2_0 || - (m_Schema.m_major == METAMODEL_MAJOR_VER_B1 && m_Schema.m_minor == METAMODEL_MINOR_VER_B1)); + // Only 2.0 of the metadata support generics + return (m_Schema.m_major >= METAMODEL_MAJOR_VER_V2_0); }// SupportGenerics protected: diff --git a/src/runtime/src/coreclr/md/runtime/mdfileformat.cpp b/src/runtime/src/coreclr/md/runtime/mdfileformat.cpp index 9b1c5f6e64b..9e9a2533027 100644 --- a/src/runtime/src/coreclr/md/runtime/mdfileformat.cpp +++ b/src/runtime/src/coreclr/md/runtime/mdfileformat.cpp @@ -18,7 +18,6 @@ //***************************************************************************** // Verify the signature at the front of the file to see what type it is. //***************************************************************************** -#define STORAGE_MAGIC_OLD_SIG 0x2B4D4F43 // +MOC (old version of BSJB signature code:STORAGE_MAGIC_SIG) HRESULT MDFormat::VerifySignature( PSTORAGESIGNATURE pSig, // The signature to check. @@ -28,11 +27,6 @@ MDFormat::VerifySignature( // If signature didn't match, you shouldn't be here. ULONG dwSignature = pSig->GetSignature(); - if (dwSignature == STORAGE_MAGIC_OLD_SIG) - { - Debug_ReportError("Invalid MetaData storage signature - old magic signature +MOC."); - return PostError(CLDB_E_FILE_OLDVER, 1, 0); - } if (dwSignature != STORAGE_MAGIC_SIG) { Debug_ReportError("Invalid MetaData storage signature - unrecognized magic signature, should be BSJB."); @@ -76,17 +70,6 @@ MDFormat::VerifySignature( } } - // Only a specific version of the 0.x format is supported by this code - // in order to support the NT 5 beta clients which used this format. - if (pSig->GetMajorVer() == FILE_VER_MAJOR_v0) - { - if (pSig->GetMinorVer() < FILE_VER_MINOR_v0) - { - Debug_ReportError("Invalid MetaData storage signature - unrecognized version, should be 1.1."); - hr = CLDB_E_FILE_OLDVER; - } - } - else // There is currently no code to migrate an old format of the 1.x. This // would be added only under special circumstances. if ((pSig->GetMajorVer() != FILE_VER_MAJOR) || (pSig->GetMinorVer() != FILE_VER_MINOR)) diff --git a/src/runtime/src/coreclr/md/runtime/mdinternalro.cpp b/src/runtime/src/coreclr/md/runtime/mdinternalro.cpp index 5e2d52eeaa9..b4ce60510cd 100644 --- a/src/runtime/src/coreclr/md/runtime/mdinternalro.cpp +++ b/src/runtime/src/coreclr/md/runtime/mdinternalro.cpp @@ -3321,63 +3321,4 @@ HRESULT MDInternalRO::ApplyEditAndContinue( return hr; } -HRESULT MDInternalRO::GetRvaOffsetData( - DWORD *pFirstMethodRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in MethodDef table. - DWORD *pMethodDefRecordSize, // [OUT] Size of each record in MethodDef table. - DWORD *pMethodDefCount, // [OUT] Number of records in MethodDef table. - DWORD *pFirstFieldRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in FieldRVA table. - DWORD *pFieldRvaRecordSize, // [OUT] Size of each record in FieldRVA table. - DWORD *pFieldRvaCount) // [OUT] Number of records in FieldRVA table. -{ - HRESULT hr = S_OK; - DWORD methodDefCount = *pMethodDefCount = m_LiteWeightStgdb.m_MiniMd.getCountMethods(); - if (methodDefCount == 0) - *pFirstMethodRvaOffset = *pMethodDefRecordSize = 0; - else - { - MethodRec *pMethodRec; - IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetMethodRecord(1, &pMethodRec)); - - // RVA is the first column of the MethodDef table, so the address of MethodRec is also address of RVA column. - if ((const BYTE *)m_LiteWeightStgdb.m_pvMd > (const BYTE *)pMethodRec) - { - Debug_ReportError("Stream header is not within MetaData block."); - IfFailGo(CLDB_E_FILE_CORRUPT); - } - *pFirstMethodRvaOffset = (DWORD)((const BYTE *)pMethodRec - (const BYTE *)m_LiteWeightStgdb.m_pvMd); - *pMethodDefRecordSize = m_LiteWeightStgdb.m_MiniMd._CBREC(Method); - } - - { - DWORD fieldRvaCount = *pFieldRvaCount = m_LiteWeightStgdb.m_MiniMd.getCountFieldRVAs(); - if (fieldRvaCount == 0) - *pFirstFieldRvaOffset = *pFieldRvaRecordSize = 0; - else - { - - // orig - // FieldRVARec *pFieldRVARec = m_LiteWeightStgdb.m_MiniMd.getFieldRVA(1); - FieldRVARec *pFieldRVARec; - IfFailGo(m_LiteWeightStgdb.m_MiniMd.GetFieldRVARecord(1, &pFieldRVARec)); - -//FieldRVARec *pFieldRVARec; -//mdToken fakeTok = 1; -//RidToToken(&fakeTok, mdtFieldDef); -//GetFieldRVA(fakeTok, &pFieldRVARec); - // RVA is the first column of the FieldRVA table, so the address of FieldRVARec is also address of RVA column. - if ((const BYTE *)m_LiteWeightStgdb.m_pvMd > (const BYTE *)pFieldRVARec) - { - Debug_ReportError("Stream header is not within MetaData block."); - IfFailGo(CLDB_E_FILE_CORRUPT); - } - *pFirstFieldRvaOffset = (DWORD)((const BYTE *)pFieldRVARec - (const BYTE *)m_LiteWeightStgdb.m_pvMd); - *pFieldRvaRecordSize = m_LiteWeightStgdb.m_MiniMd._CBREC(FieldRVA); - } - } - hr = S_OK; - -ErrExit: - return hr; -} - #endif //FEATURE_METADATA_INTERNAL_APIS diff --git a/src/runtime/src/coreclr/md/runtime/mdinternalro.h b/src/runtime/src/coreclr/md/runtime/mdinternalro.h index 5f46a34b0ff..8ea00e1b908 100644 --- a/src/runtime/src/coreclr/md/runtime/mdinternalro.h +++ b/src/runtime/src/coreclr/md/runtime/mdinternalro.h @@ -66,13 +66,6 @@ class MDInternalRO : public IMDInternalImport, IMDCommon return static_cast(&m_LiteWeightStgdb.m_MiniMd); } - __checkReturn - STDMETHODIMP SetOptimizeAccessForSpeed( - BOOL fOptSpeed) - { - return S_OK; - } - //***************************************************************************** // return the count of entries of a given kind in a scope // For example, pass in mdtMethodDef will tell you how many MethodDef @@ -734,15 +727,6 @@ class MDInternalRO : public IMDInternalImport, IMDCommon ULONG cbData, // [IN] length of pData IMDInternalImport **ppv); // [OUT] the resulting metadata interface - STDMETHODIMP GetRvaOffsetData( - DWORD *pFirstMethodRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in MethodDef table. - DWORD *pMethodDefRecordSize, // [OUT] Size of each record in MethodDef table. - DWORD *pMethodDefCount, // [OUT] Number of records in MethodDef table. - DWORD *pFirstFieldRvaOffset, // [OUT] Offset (from start of metadata) to the first RVA field in FieldRVA table. - DWORD *pFieldRvaRecordSize, // [OUT] Size of each record in FieldRVA table. - DWORD *pFieldRvaCount // [OUT] Number of records in FieldRVA table. - ); - CLiteWeightStgdb m_LiteWeightStgdb; private: @@ -784,12 +768,6 @@ class MDInternalRO : public IMDInternalImport, IMDCommon ((DWORD)m_LiteWeightStgdb.m_MiniMd.m_Schema.m_major << 16); }; - STDMETHODIMP SetVerifiedByTrustedSource(// return hresult - BOOL fVerified) - { - m_LiteWeightStgdb.m_MiniMd.SetVerifiedByTrustedSource(fVerified); - return S_OK; - } }; // class MDInternalRO #endif //FEATURE_METADATA_INTERNAL_APIS diff --git a/src/runtime/src/coreclr/md/runtime/metamodel.cpp b/src/runtime/src/coreclr/md/runtime/metamodel.cpp index aca6fefbcdc..b02f6553c63 100644 --- a/src/runtime/src/coreclr/md/runtime/metamodel.cpp +++ b/src/runtime/src/coreclr/md/runtime/metamodel.cpp @@ -106,10 +106,6 @@ const CMiniTableDefEx g_Tables[TBL_COUNT] = { #endif }; -// Define a table descriptor for the obsolete v1.0 GenericParam table definition. -const CMiniTableDefEx g_Table_GenericParamV1_1 = { { rGenericParamV1_1Cols, ARRAY_SIZE(rGenericParamV1_1Cols), GenericParamV1_1Rec::COL_KEY, 0 }, rGenericParamV1_1ColNames, "GenericParamV1_"}; - - // Define the array of Ptr Tables. This is initialized to TBL_COUNT here. // The correct values will be set in the constructor for MiniMdRW. @@ -187,10 +183,7 @@ CMiniMdSchema::SaveTo( // Minor version is preset when we instantiate the MiniMd. - // Make sure we're saving out a version that Beta1 version can read - _ASSERTE((m_major == METAMODEL_MAJOR_VER && m_minor == METAMODEL_MINOR_VER) || - (m_major == METAMODEL_MAJOR_VER_B1 && m_minor == METAMODEL_MINOR_VER_B1) || - (m_major == METAMODEL_MAJOR_VER_V1_0 && m_minor == METAMODEL_MINOR_VER_V1_0)); + _ASSERTE((m_major == METAMODEL_MAJOR_VER) && (m_minor == METAMODEL_MINOR_VER)); // Transfer the fixed fields. *static_cast(pDest) = *static_cast(this); @@ -555,13 +548,6 @@ CMiniMdBase::SchemaPopulate( // Older version has fewer tables. m_TblCount = TBL_COUNT_V1; } - else if ((m_Schema.m_major == METAMODEL_MAJOR_VER_B1) && - (m_Schema.m_minor == METAMODEL_MINOR_VER_B1)) - { - // 1.1 had a different type of GenericParam table - m_TableDefs[TBL_GenericParam] = g_Table_GenericParamV1_1.m_Def; - m_TableDefs[TBL_GenericParam].m_pColDefs = BYTEARRAY_TO_COLDES(s_GenericParamCol); - } else { // We don't support this version of the metadata Debug_ReportError("Unsupported version of MetaData."); @@ -602,12 +588,6 @@ CMiniMdBase::SchemaPopulate( m_TblCount = that.m_TblCount; _ASSERTE(m_TblCount == TBL_COUNT_V1); } - else if (m_Schema.m_major == METAMODEL_MAJOR_VER_B1 && m_Schema.m_minor == METAMODEL_MINOR_VER_B1) - { - // 1.1 had a different type of GenericParam table - m_TableDefs[TBL_GenericParam] = g_Table_GenericParamV1_1.m_Def; - m_TableDefs[TBL_GenericParam].m_pColDefs = BYTEARRAY_TO_COLDES(s_GenericParamCol); - } // Is it a supported old version? This should never fail! else { @@ -689,19 +669,7 @@ const CMiniTableDef * CMiniMdBase::GetTableDefTemplate( int ixTbl) { - const CMiniTableDef *pTemplate; // the return value. - - // Return the table definition for the given table. Account for version of schema. - if ((m_Schema.m_major == METAMODEL_MAJOR_VER_B1) && (m_Schema.m_minor == METAMODEL_MINOR_VER_B1) && (ixTbl == TBL_GenericParam)) - { - pTemplate = &g_Table_GenericParamV1_1.m_Def; - } - else - { - pTemplate = &g_Tables[ixTbl].m_Def; - } - - return pTemplate; + return &g_Tables[ixTbl].m_Def; } // CMiniMdBase::GetTableDefTemplate //***************************************************************************** diff --git a/src/runtime/src/coreclr/nativeaot/BuildIntegration/BuildIntegration.proj b/src/runtime/src/coreclr/nativeaot/BuildIntegration/BuildIntegration.proj index 846e3b392a8..09ae560bcb0 100644 --- a/src/runtime/src/coreclr/nativeaot/BuildIntegration/BuildIntegration.proj +++ b/src/runtime/src/coreclr/nativeaot/BuildIntegration/BuildIntegration.proj @@ -1,34 +1,9 @@ - - - + $(RuntimeBinDir)/build/ - + - - - - - - - - - - - - - - - diff --git a/src/runtime/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets b/src/runtime/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets index 3e8c0678afe..f2bf303e494 100644 --- a/src/runtime/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets +++ b/src/runtime/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.Unix.targets @@ -222,7 +222,7 @@ The .NET Foundation licenses this file to you under the MIT license. - + diff --git a/src/runtime/src/coreclr/runtime.proj b/src/runtime/src/coreclr/runtime.proj index 68c005b948f..1286ba903d8 100644 --- a/src/runtime/src/coreclr/runtime.proj +++ b/src/runtime/src/coreclr/runtime.proj @@ -120,5 +120,25 @@ IgnoreStandardErrorWarningFormat="true" /> + + + + + + + + + + diff --git a/src/runtime/src/coreclr/tools/aot/Directory.Build.targets b/src/runtime/src/coreclr/tools/aot/Directory.Build.targets index 4f855d71288..2919d6e7022 100644 --- a/src/runtime/src/coreclr/tools/aot/Directory.Build.targets +++ b/src/runtime/src/coreclr/tools/aot/Directory.Build.targets @@ -1,6 +1,11 @@ + + true + true + + diff --git a/src/runtime/src/coreclr/tools/aot/ILCompiler/ILCompiler.props b/src/runtime/src/coreclr/tools/aot/ILCompiler/ILCompiler.props index 459594303a3..5ae9f528f50 100644 --- a/src/runtime/src/coreclr/tools/aot/ILCompiler/ILCompiler.props +++ b/src/runtime/src/coreclr/tools/aot/ILCompiler/ILCompiler.props @@ -13,11 +13,9 @@ true false Debug;Release;Checked - true - diff --git a/src/runtime/src/coreclr/tools/aot/ILCompiler/ILCompiler_inbuild.csproj b/src/runtime/src/coreclr/tools/aot/ILCompiler/ILCompiler_inbuild.csproj index d22aff2a1de..de290906b2e 100644 --- a/src/runtime/src/coreclr/tools/aot/ILCompiler/ILCompiler_inbuild.csproj +++ b/src/runtime/src/coreclr/tools/aot/ILCompiler/ILCompiler_inbuild.csproj @@ -15,7 +15,7 @@ false - + true true diff --git a/src/runtime/src/coreclr/tools/aot/ILCompiler/ILCompiler_publish.csproj b/src/runtime/src/coreclr/tools/aot/ILCompiler/ILCompiler_publish.csproj index d49edad34c4..b8a82d9d550 100644 --- a/src/runtime/src/coreclr/tools/aot/ILCompiler/ILCompiler_publish.csproj +++ b/src/runtime/src/coreclr/tools/aot/ILCompiler/ILCompiler_publish.csproj @@ -2,17 +2,14 @@ <_IsPublishing>true - $(OutputRID) - - $(BaseOS) + + $(PortableOS)-$(TargetArchitecture) $(RuntimeBinDir)ilc-published/ true true false true + true diff --git a/src/runtime/src/coreclr/tools/aot/crossgen2/crossgen2.props b/src/runtime/src/coreclr/tools/aot/crossgen2/crossgen2.props index b2ce7bf7599..d2ed5e4bfcc 100644 --- a/src/runtime/src/coreclr/tools/aot/crossgen2/crossgen2.props +++ b/src/runtime/src/coreclr/tools/aot/crossgen2/crossgen2.props @@ -15,11 +15,9 @@ false Debug;Release;Checked false - true - diff --git a/src/runtime/src/coreclr/tools/aot/crossgen2/crossgen2_inbuild.csproj b/src/runtime/src/coreclr/tools/aot/crossgen2/crossgen2_inbuild.csproj index f7752670e40..6f040291280 100644 --- a/src/runtime/src/coreclr/tools/aot/crossgen2/crossgen2_inbuild.csproj +++ b/src/runtime/src/coreclr/tools/aot/crossgen2/crossgen2_inbuild.csproj @@ -15,7 +15,7 @@ false - + true true diff --git a/src/runtime/src/coreclr/tools/aot/crossgen2/crossgen2_publish.csproj b/src/runtime/src/coreclr/tools/aot/crossgen2/crossgen2_publish.csproj index 8e81546a277..3a4bd39472d 100644 --- a/src/runtime/src/coreclr/tools/aot/crossgen2/crossgen2_publish.csproj +++ b/src/runtime/src/coreclr/tools/aot/crossgen2/crossgen2_publish.csproj @@ -2,17 +2,14 @@ <_IsPublishing>true - $(OutputRID) - - $(BaseOS) + + $(PortableOS)-$(TargetArchitecture) $(RuntimeBinDir)crossgen2-published/ true true false true + true diff --git a/src/runtime/src/coreclr/utilcode/util.cpp b/src/runtime/src/coreclr/utilcode/util.cpp index f3dc7864171..dac90c2ad97 100644 --- a/src/runtime/src/coreclr/utilcode/util.cpp +++ b/src/runtime/src/coreclr/utilcode/util.cpp @@ -1923,35 +1923,6 @@ HRESULT validateTokenSig( return S_OK; } // validateTokenSig() -HRESULT GetImageRuntimeVersionString(PVOID pMetaData, LPCSTR* pString) -{ - CONTRACTL - { - NOTHROW; - } - CONTRACTL_END; - - _ASSERTE(pString); - STORAGESIGNATURE* pSig = (STORAGESIGNATURE*) pMetaData; - - // Verify the signature. - - // If signature didn't match, you shouldn't be here. - if (pSig->GetSignature() != STORAGE_MAGIC_SIG) - return CLDB_E_FILE_CORRUPT; - - // The version started in version 1.1 - if (pSig->GetMajorVer() < 1) - return CLDB_E_FILE_OLDVER; - - if (pSig->GetMajorVer() == 1 && pSig->GetMinorVer() < 1) - return CLDB_E_FILE_OLDVER; - - // Header data starts after signature. - *pString = (LPCSTR) pSig->pVersion; - return S_OK; -} - //***************************************************************************** // Convert a UTF8 string to Unicode, into a CQuickArray. //***************************************************************************** diff --git a/src/runtime/src/coreclr/vm/FrameTypes.h b/src/runtime/src/coreclr/vm/FrameTypes.h index cbbfb028d55..19c5092466e 100644 --- a/src/runtime/src/coreclr/vm/FrameTypes.h +++ b/src/runtime/src/coreclr/vm/FrameTypes.h @@ -14,9 +14,7 @@ FRAME_TYPE_NAME(ResumableFrame) FRAME_TYPE_NAME(RedirectedThreadFrame) #endif // FEATURE_HIJACK FRAME_TYPE_NAME(FaultingExceptionFrame) -#ifdef FEATURE_EH_FUNCLETS FRAME_TYPE_NAME(SoftwareExceptionFrame) -#endif // FEATURE_EH_FUNCLETS #ifdef DEBUGGING_SUPPORTED FRAME_TYPE_NAME(FuncEvalFrame) #endif // DEBUGGING_SUPPORTED diff --git a/src/runtime/src/coreclr/vm/amd64/JitHelpers_Slow.asm b/src/runtime/src/coreclr/vm/amd64/JitHelpers_Slow.asm index 63bc8cc43f1..8b1fbbb7f8d 100644 --- a/src/runtime/src/coreclr/vm/amd64/JitHelpers_Slow.asm +++ b/src/runtime/src/coreclr/vm/amd64/JitHelpers_Slow.asm @@ -40,8 +40,6 @@ EXTERN g_GCShadowEnd:QWORD endif JIT_NEW equ ?JIT_New@@YAPEAVObject@@PEAUCORINFO_CLASS_STRUCT_@@@Z -CopyValueClassUnchecked equ ?CopyValueClassUnchecked@@YAXPEAX0PEAVMethodTable@@@Z -JIT_Box equ ?JIT_Box@@YAPEAVObject@@PEAUCORINFO_CLASS_STRUCT_@@PEAX@Z g_pStringClass equ ?g_pStringClass@@3PEAVMethodTable@@EA FramedAllocateString equ ?FramedAllocateString@@YAPEAVStringObject@@K@Z JIT_NewArr1 equ ?JIT_NewArr1@@YAPEAVObject@@PEAUCORINFO_CLASS_STRUCT_@@_J@Z @@ -49,8 +47,6 @@ JIT_NewArr1 equ ?JIT_NewArr1@@YAPEAVObject@@PEAUCORINFO_CLASS_ST INVALIDGCVALUE equ 0CCCCCCCDh extern JIT_NEW:proc -extern CopyValueClassUnchecked:proc -extern JIT_Box:proc extern g_pStringClass:QWORD extern FramedAllocateString:proc extern JIT_NewArr1:proc @@ -197,69 +193,6 @@ LEAF_ENTRY JIT_TrialAllocSFastSP, _TEXT jmp JIT_NEW LEAF_END JIT_TrialAllocSFastSP, _TEXT -; HCIMPL2(Object*, JIT_Box, CORINFO_CLASS_HANDLE type, void* unboxedData) -NESTED_ENTRY JIT_BoxFastUP, _TEXT - - ; m_BaseSize is guaranteed to be a multiple of 8. - mov r8d, [rcx + OFFSET__MethodTable__m_BaseSize] - - inc [g_global_alloc_lock] - jnz JIT_Box - - mov rax, [g_global_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr] ; alloc_ptr - mov r10, [g_global_alloc_context + OFFSETOF__ee_alloc_context__m_CombinedLimit] ; m_CombinedLimit - - add r8, rax - - cmp r8, r10 - ja NoAlloc - - test rdx, rdx - je NullRef - - mov qword ptr [g_global_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr], r8 ; update the alloc ptr - mov [rax], rcx - mov [g_global_alloc_lock], -1 - - ; Check whether the object contains pointers - test dword ptr [rcx + OFFSETOF__MethodTable__m_dwFlags], MethodTable__enum_flag_ContainsGCPointers - jnz ContainsPointers - - ; We have no pointers - emit a simple inline copy loop - - mov ecx, [rcx + OFFSET__MethodTable__m_BaseSize] - sub ecx, 18h ; sizeof(ObjHeader) + sizeof(Object) + last slot - - CopyLoop: - mov r8, [rdx+rcx] - mov [rax+rcx+8], r8 - - sub ecx, 8 - jge CopyLoop - REPRET - - ContainsPointers: - - ; Do call to CopyValueClassUnchecked(object, data, pMT) - - push_vol_reg rax - alloc_stack 20h - END_PROLOGUE - - mov r8, rcx - lea rcx, [rax + 8] - call CopyValueClassUnchecked - - add rsp, 20h - pop rax - ret - - NoAlloc: - NullRef: - mov [g_global_alloc_lock], -1 - jmp JIT_Box -NESTED_END JIT_BoxFastUP, _TEXT - LEAF_ENTRY AllocateStringFastUP, _TEXT ; We were passed the number of characters in ECX diff --git a/src/runtime/src/coreclr/vm/amd64/cgencpu.h b/src/runtime/src/coreclr/vm/amd64/cgencpu.h index 1f118ca0e80..10c7124c204 100644 --- a/src/runtime/src/coreclr/vm/amd64/cgencpu.h +++ b/src/runtime/src/coreclr/vm/amd64/cgencpu.h @@ -450,6 +450,46 @@ inline TADDR GetFP(const CONTEXT * context) return (TADDR)(context->Rbp); } +inline void SetFirstArgReg(CONTEXT *context, TADDR value) +{ + LIMITED_METHOD_DAC_CONTRACT; +#ifdef UNIX_AMD64_ABI + context->Rdi = (DWORD64)value; +#else + context->Rcx = (DWORD64)value; +#endif +} + +inline TADDR GetFirstArgReg(CONTEXT *context) +{ + LIMITED_METHOD_DAC_CONTRACT; +#ifdef UNIX_AMD64_ABI + return (TADDR)(context->Rdi); +#else + return (TADDR)(context->Rcx); +#endif +} + +inline void SetSecondArgReg(CONTEXT *context, TADDR value) +{ + LIMITED_METHOD_DAC_CONTRACT; +#ifdef UNIX_AMD64_ABI + context->Rsi = (DWORD64)value; +#else + context->Rdx = (DWORD64)value; +#endif +} + +inline TADDR GetSecondArgReg(CONTEXT *context) +{ + LIMITED_METHOD_DAC_CONTRACT; +#ifdef UNIX_AMD64_ABI + return (TADDR)(context->Rsi); +#else + return (TADDR)(context->Rdx); +#endif +} + extern "C" TADDR GetCurrentSP(); // Emits: diff --git a/src/runtime/src/coreclr/vm/arm/cgencpu.h b/src/runtime/src/coreclr/vm/arm/cgencpu.h index 6ae9d7e3b58..8f2f6e72a41 100644 --- a/src/runtime/src/coreclr/vm/arm/cgencpu.h +++ b/src/runtime/src/coreclr/vm/arm/cgencpu.h @@ -255,6 +255,30 @@ inline TADDR GetFP(const T_CONTEXT * context) return (TADDR)(context->R11); } +inline void SetFirstArgReg(T_CONTEXT *context, TADDR value) +{ + LIMITED_METHOD_DAC_CONTRACT; + context->R0 = DWORD(value); +} + +inline TADDR GetFirstArgReg(T_CONTEXT *context) +{ + LIMITED_METHOD_DAC_CONTRACT; + return (TADDR)(context->R0); +} + +inline void SetSecondArgReg(T_CONTEXT *context, TADDR value) +{ + LIMITED_METHOD_DAC_CONTRACT; + context->R1 = DWORD(value); +} + +inline TADDR GetSecondArgReg(T_CONTEXT *context) +{ + LIMITED_METHOD_DAC_CONTRACT; + return (TADDR)(context->R1); +} + inline void ClearITState(T_CONTEXT *context) { LIMITED_METHOD_DAC_CONTRACT; context->Cpsr = context->Cpsr & 0xf9ff03ff; diff --git a/src/runtime/src/coreclr/vm/arm/stubs.cpp b/src/runtime/src/coreclr/vm/arm/stubs.cpp index e28af8bcd67..4dd096adc50 100644 --- a/src/runtime/src/coreclr/vm/arm/stubs.cpp +++ b/src/runtime/src/coreclr/vm/arm/stubs.cpp @@ -1652,7 +1652,6 @@ void InitJITHelpers1() SetJitHelperFunction(CORINFO_HELP_NEWSFAST, JIT_NewS_MP_FastPortable); SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1VC_MP_FastPortable); SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP_FastPortable); - SetJitHelperFunction(CORINFO_HELP_BOX, JIT_Box_MP_FastPortable); ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateString_MP_FastPortable), ECall::FastAllocateString); } diff --git a/src/runtime/src/coreclr/vm/arm64/cgencpu.h b/src/runtime/src/coreclr/vm/arm64/cgencpu.h index 9f6f86532ff..7e7ef46877e 100644 --- a/src/runtime/src/coreclr/vm/arm64/cgencpu.h +++ b/src/runtime/src/coreclr/vm/arm64/cgencpu.h @@ -279,6 +279,29 @@ inline TADDR GetFP(const T_CONTEXT * context) return (TADDR)(context->Fp); } +inline void SetFirstArgReg(T_CONTEXT *context, TADDR value) +{ + LIMITED_METHOD_DAC_CONTRACT; + SetReg(context, 0, value); +} + +inline TADDR GetFirstArgReg(T_CONTEXT *context) +{ + LIMITED_METHOD_DAC_CONTRACT; + return GetReg(context, 0); +} + +inline void SetSecondArgReg(T_CONTEXT *context, TADDR value) +{ + LIMITED_METHOD_DAC_CONTRACT; + SetReg(context, 1, value); +} + +inline TADDR GetSecondArgReg(T_CONTEXT *context) +{ + LIMITED_METHOD_DAC_CONTRACT; + return GetReg(context, 1); +} inline TADDR GetMem(PCODE address, SIZE_T size, bool signExtend) { diff --git a/src/runtime/src/coreclr/vm/arm64/stubs.cpp b/src/runtime/src/coreclr/vm/arm64/stubs.cpp index 751595b9f52..53fe10b5488 100644 --- a/src/runtime/src/coreclr/vm/arm64/stubs.cpp +++ b/src/runtime/src/coreclr/vm/arm64/stubs.cpp @@ -878,7 +878,6 @@ void InitJITHelpers1() SetJitHelperFunction(CORINFO_HELP_NEWSFAST_ALIGN8, JIT_NewS_MP_FastPortable); SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1VC_MP_FastPortable); SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP_FastPortable); - SetJitHelperFunction(CORINFO_HELP_BOX, JIT_Box_MP_FastPortable); ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateString_MP_FastPortable), ECall::FastAllocateString); } diff --git a/src/runtime/src/coreclr/vm/corelib.h b/src/runtime/src/coreclr/vm/corelib.h index fe86ea43697..ba3c64b7e08 100644 --- a/src/runtime/src/coreclr/vm/corelib.h +++ b/src/runtime/src/coreclr/vm/corelib.h @@ -1249,10 +1249,12 @@ DEFINE_METHOD(CASTHELPERS, CHKCASTANY, ChkCastAny, SM_Ptr DEFINE_METHOD(CASTHELPERS, CHKCASTINTERFACE, ChkCastInterface, SM_PtrVoid_Obj_RetObj) DEFINE_METHOD(CASTHELPERS, CHKCASTCLASS, ChkCastClass, SM_PtrVoid_Obj_RetObj) DEFINE_METHOD(CASTHELPERS, CHKCASTCLASSSPECIAL, ChkCastClassSpecial, SM_PtrVoid_Obj_RetObj) +DEFINE_METHOD(CASTHELPERS, BOX, Box, NoSig) DEFINE_METHOD(CASTHELPERS, UNBOX, Unbox, NoSig) DEFINE_METHOD(CASTHELPERS, STELEMREF, StelemRef, SM_ArrObject_IntPtr_Obj_RetVoid) DEFINE_METHOD(CASTHELPERS, LDELEMAREF, LdelemaRef, SM_ArrObject_IntPtr_PtrVoid_RetRefObj) DEFINE_METHOD(CASTHELPERS, ARRAYTYPECHECK, ArrayTypeCheck, SM_Obj_Array_RetVoid) +DEFINE_METHOD(CASTHELPERS, BOX_NULLABLE, Box_Nullable, NoSig) DEFINE_METHOD(CASTHELPERS, UNBOX_NULLABLE, Unbox_Nullable, NoSig) DEFINE_METHOD(CASTHELPERS, UNBOX_TYPETEST, Unbox_TypeTest, NoSig) diff --git a/src/runtime/src/coreclr/vm/ecalllist.h b/src/runtime/src/coreclr/vm/ecalllist.h index 7fa6ae288bb..f3102c0f4ac 100644 --- a/src/runtime/src/coreclr/vm/ecalllist.h +++ b/src/runtime/src/coreclr/vm/ecalllist.h @@ -97,6 +97,7 @@ FCFuncStart(gCOMTypeHandleFuncs) FCFuncElement("ContainsGenericVariables", RuntimeTypeHandle::ContainsGenericVariables) FCFuncElement("IsUnmanagedFunctionPointer", RuntimeTypeHandle::IsUnmanagedFunctionPointer) FCFuncElement("CompareCanonicalHandles", RuntimeTypeHandle::CompareCanonicalHandles) + FCFuncElement("InternalAllocNoChecks_FastPath", RuntimeTypeHandle::InternalAllocNoChecks_FastPath) FCFuncEnd() FCFuncStart(gMetaDataImport) @@ -337,7 +338,6 @@ FCFuncStart(gRuntimeHelpers) FCFuncElement("TryEnsureSufficientExecutionStack", ReflectionInvocation::TryEnsureSufficientExecutionStack) FCFuncElement("AllocTailCallArgBufferWorker", TailCallHelp::AllocTailCallArgBufferWorker) FCFuncElement("GetTailCallInfo", TailCallHelp::GetTailCallInfo) - FCFuncElement("Box", JIT_Box) FCFuncEnd() FCFuncStart(gMethodTableFuncs) diff --git a/src/runtime/src/coreclr/vm/eetwain.cpp b/src/runtime/src/coreclr/vm/eetwain.cpp index 189c2edca45..d6832774c12 100644 --- a/src/runtime/src/coreclr/vm/eetwain.cpp +++ b/src/runtime/src/coreclr/vm/eetwain.cpp @@ -22,6 +22,7 @@ #endif // FEATURE_INTERPRETER #include "exinfo.h" +#include "excep.h" #ifdef TARGET_X86 @@ -2075,6 +2076,71 @@ DWORD_PTR EECodeManager::CallFunclet(OBJECTREF throwable, void* pHandler, REGDIS return dwResult; } +void EECodeManager::ResumeAfterCatch(CONTEXT *pContext, size_t targetSSP, bool fIntercepted) +{ + Thread *pThread = GetThread(); + DWORD_PTR dwResumePC = GetIP(pContext); + UINT_PTR uAbortAddr = 0; + if (!fIntercepted) + { + CopyOSContext(pThread->m_OSContext, pContext); + uAbortAddr = (UINT_PTR)COMPlusCheckForAbort(dwResumePC); + } + + if (uAbortAddr) + { + STRESS_LOG2(LF_EH, LL_INFO10, "Thread abort in progress, resuming under control: IP=%p, SP=%p\n", dwResumePC, GetSP(pContext)); + + // The dwResumePC is passed to the THROW_CONTROL_FOR_THREAD_FUNCTION ASM helper so that + // it can establish it as its return address and native stack unwinding can work properly. +#ifdef TARGET_AMD64 +#ifdef TARGET_UNIX + pContext->Rdi = dwResumePC; +#else + pContext->Rcx = dwResumePC; +#endif +#elif defined(TARGET_ARM) || defined(TARGET_ARM64) + // On ARM & ARM64, we save off the original PC in Lr. This is the same as done + // in HandleManagedFault for H/W generated exceptions. + pContext->Lr = dwResumePC; +#elif defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) + pContext->Ra = dwResumePC; +#endif + + SetIP(pContext, uAbortAddr); + } + else + { + STRESS_LOG2(LF_EH, LL_INFO100, "Resuming after exception at IP=%p, SP=%p\n", GetIP(pContext), GetSP(pContext)); + } + + ClrRestoreNonvolatileContext(pContext, targetSSP); +} + +#if defined(HOST_AMD64) && defined(HOST_WINDOWS) + +size_t GetSSPForFrameOnCurrentStack(TADDR ip) +{ + size_t *targetSSP = (size_t *)_rdsspq(); + // The SSP we search is pointing to the return address of the frame represented + // by the passed in IP. So we search for the instruction pointer from + // the context and return one slot up from there. + if (targetSSP != NULL) + { + while (*targetSSP++ != ip) + { + } + } + + return (size_t)targetSSP; +} + +void EECodeManager::UpdateSSP(PREGDISPLAY pRD) +{ + pRD->SSP = GetSSPForFrameOnCurrentStack(pRD->ControlPC); +} +#endif // HOST_AMD64 && HOST_WINDOWS + #ifdef FEATURE_INTERPRETER DWORD_PTR InterpreterCodeManager::CallFunclet(OBJECTREF throwable, void* pHandler, REGDISPLAY *pRD, ExInfo *pExInfo, bool isFilter) { @@ -2082,6 +2148,72 @@ DWORD_PTR InterpreterCodeManager::CallFunclet(OBJECTREF throwable, void* pHandle _ASSERTE(FALSE); return 0; } + +void InterpreterCodeManager::ResumeAfterCatch(CONTEXT *pContext, size_t targetSSP, bool fIntercepted) +{ + Thread *pThread = GetThread(); + InterpreterFrame * pInterpreterFrame = (InterpreterFrame*)pThread->GetFrame(); + TADDR resumeSP = GetSP(pContext); + TADDR resumeIP = GetIP(pContext); + + ClrCaptureContext(pContext); + + // Unwind to the caller of the Ex.RhThrowEx / Ex.RhThrowHwEx + Thread::VirtualUnwindToFirstManagedCallFrame(pContext); + +#if defined(HOST_AMD64) && defined(HOST_WINDOWS) + targetSSP = GetSSPForFrameOnCurrentStack(GetIP(pContext)); +#endif // HOST_AMD64 && HOST_WINDOWS + + CONTEXT firstNativeContext; + size_t firstNativeSSP; + + // Find the native frames chain that contains the resumeSP + do + { + // Skip all managed frames upto a native frame + while (ExecutionManager::IsManagedCode(GetIP(pContext))) + { + Thread::VirtualUnwindCallFrame(pContext); +#if defined(HOST_AMD64) && defined(HOST_WINDOWS) + if (targetSSP != 0) + { + targetSSP += sizeof(size_t); + } +#endif + } + + // Save the first native context after managed frames. This will be the context where we throw the resume after catch exception from. + firstNativeContext = *pContext; + firstNativeSSP = targetSSP; + // Move over all native frames until we move over the resumeSP + while ((GetSP(pContext) < resumeSP) && !ExecutionManager::IsManagedCode(GetIP(pContext))) + { +#ifdef TARGET_UNIX + PAL_VirtualUnwind(pContext, NULL); +#else + Thread::VirtualUnwindCallFrame(pContext); +#endif +#if defined(HOST_AMD64) && defined(HOST_WINDOWS) + if (targetSSP != 0) + { + targetSSP += sizeof(size_t); + } +#endif + } + } + while (GetSP(pContext) < resumeSP); + + ExecuteFunctionBelowContext((PCODE)ThrowResumeAfterCatchException, &firstNativeContext, firstNativeSSP, resumeSP, resumeIP); +} + +#if defined(HOST_AMD64) && defined(HOST_WINDOWS) +void InterpreterCodeManager::UpdateSSP(PREGDISPLAY pRD) +{ + InterpreterFrame* pFrame = (InterpreterFrame*)GetFirstArgReg(pRD->pCurrentContext); + pRD->SSP = pFrame->GetInterpExecMethodSSP(); +} +#endif // HOST_AMD64 && HOST_WINDOWS #endif // FEATURE_INTERPRETER #endif // !FEATURE_EH_FUNCLETS @@ -2241,7 +2373,7 @@ static void VirtualUnwindInterpreterCallFrame(TADDR sp, T_CONTEXT *pContext) SetIP(pContext, 0); SetSP(pContext, sp); } - pContext->ContextFlags = CONTEXT_CONTROL; + pContext->ContextFlags = CONTEXT_FULL; } bool InterpreterCodeManager::UnwindStackFrame(PREGDISPLAY pRD, @@ -2273,7 +2405,7 @@ bool InterpreterCodeManager::UnwindStackFrame(PREGDISPLAY pRD, return true; } -void InterpreterCodeManager::EnsureCallerContextIsValid( PREGDISPLAY pRD, EECodeInfo * pCodeInfo /*= NULL*/, unsigned flags /*= 0*/) +void InterpreterCodeManager::EnsureCallerContextIsValid(PREGDISPLAY pRD, EECodeInfo * pCodeInfo /*= NULL*/, unsigned flags /*= 0*/) { CONTRACTL { @@ -2286,9 +2418,11 @@ void InterpreterCodeManager::EnsureCallerContextIsValid( PREGDISPLAY pRD, EECod if( !pRD->IsCallerContextValid ) { // We need to make a copy here (instead of switching the pointers), in order to preserve the current context + *(pRD->pCallerContext) = *(pRD->pCurrentContext); TADDR sp = (TADDR)GetRegdisplaySP(pRD); VirtualUnwindInterpreterCallFrame(sp, pRD->pCallerContext); - memset(pRD->pCallerContextPointers, 0, sizeof(KNONVOLATILE_CONTEXT_POINTERS)); + // Preserve the context pointers, they are used by floating point registers unwind starting at the original context. + memcpy(pRD->pCallerContextPointers, pRD->pCurrentContextPointers, sizeof(KNONVOLATILE_CONTEXT_POINTERS)); pRD->IsCallerContextValid = TRUE; } diff --git a/src/runtime/src/coreclr/vm/excep.cpp b/src/runtime/src/coreclr/vm/excep.cpp index 9138789ca24..726384d6495 100644 --- a/src/runtime/src/coreclr/vm/excep.cpp +++ b/src/runtime/src/coreclr/vm/excep.cpp @@ -7307,6 +7307,50 @@ VOID DECLSPEC_NORETURN UnwindAndContinueRethrowHelperAfterCatch(Frame* pEntryFra } } +#if defined(HOST_AMD64) && defined(HOST_WINDOWS) +size_t GetSSPForFrameOnCurrentStack(TADDR ip); +#endif // HOST_AMD64 && HOST_WINDOWS + +#ifdef FEATURE_INTERPRETER +void ThrowResumeAfterCatchException(TADDR resumeSP, TADDR resumeIP) +{ + throw ResumeAfterCatchException(resumeSP, resumeIP); +} + +VOID DECLSPEC_NORETURN UnwindAndContinueResumeAfterCatch(TADDR resumeSP, TADDR resumeIP) +{ + STATIC_CONTRACT_NOTHROW; + STATIC_CONTRACT_GC_TRIGGERS; + STATIC_CONTRACT_MODE_ANY; + + CONTEXT context; + ClrCaptureContext(&context); + + // Unwind to the caller of the Ex.RhThrowEx / Ex.RhThrowHwEx + Thread::VirtualUnwindToFirstManagedCallFrame(&context); + +#if defined(HOST_AMD64) && defined(HOST_WINDOWS) + size_t targetSSP = GetSSPForFrameOnCurrentStack(GetIP(&context)); +#else + size_t targetSSP = 0; +#endif + + // Skip all managed frames upto a native frame + while (ExecutionManager::IsManagedCode(GetIP(&context))) + { + Thread::VirtualUnwindCallFrame(&context); +#if defined(HOST_AMD64) && defined(HOST_WINDOWS) + if (targetSSP != 0) + { + targetSSP += sizeof(size_t); + } +#endif + } + + ExecuteFunctionBelowContext((PCODE)ThrowResumeAfterCatchException, &context, targetSSP, resumeSP, resumeIP); +} +#endif // FEATURE_INTERPRETER + thread_local DWORD t_dwCurrentExceptionCode; thread_local PEXCEPTION_RECORD t_pCurrentExceptionRecord; thread_local PCONTEXT t_pCurrentExceptionContext; @@ -11271,12 +11315,11 @@ MethodDesc * GetUserMethodForILStub(Thread * pThread, UINT_PTR uStubSP, MethodDe } -#ifdef FEATURE_EH_FUNCLETS - void SoftwareExceptionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats) { LIMITED_METHOD_DAC_CONTRACT; +#ifdef FEATURE_EH_FUNCLETS #define CALLEE_SAVED_REGISTER(regname) pRD->pCurrentContext->regname = *dac_cast((TADDR)m_ContextPointers.regname); ENUM_CALLEE_SAVED_REGISTERS(); #undef CALLEE_SAVED_REGISTER @@ -11297,6 +11340,16 @@ void SoftwareExceptionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool u pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. +#elif defined(TARGET_X86) +#define CALLEE_SAVED_REGISTER(regname) pRD->Set##regname##Location(m_ContextPointers.regname); + ENUM_CALLEE_SAVED_REGISTERS(); +#undef CALLEE_SAVED_REGISTER + + pRD->ControlPC = ::GetIP(&m_Context); + pRD->SP = ::GetSP(&m_Context); +#else // FEATURE_EH_FUNCLETS + PORTABILITY_ASSERT("SoftwareExceptionFrame::UpdateRegDisplay_Impl"); +#endif // FEATURE_EH_FUNCLETS } #ifndef DACCESS_COMPILE @@ -11377,4 +11430,3 @@ void SoftwareExceptionFrame::InitAndLink(Thread *pThread) } #endif // DACCESS_COMPILE -#endif // FEATURE_EH_FUNCLETS diff --git a/src/runtime/src/coreclr/vm/excep.h b/src/runtime/src/coreclr/vm/excep.h index ad01a65b768..d3235b8c2e5 100644 --- a/src/runtime/src/coreclr/vm/excep.h +++ b/src/runtime/src/coreclr/vm/excep.h @@ -807,6 +807,10 @@ X86_ONLY(EXCEPTION_REGISTRATION_RECORD* GetNextCOMPlusSEHRecord(EXCEPTION_REGIST VOID DECLSPEC_NORETURN ContinueExceptionInterceptionUnwind(); #endif // FEATURE_EH_FUNCLETS +#ifdef FEATURE_INTERPRETER +void ThrowResumeAfterCatchException(TADDR resumeSP, TADDR resumeIP); +#endif // FEATURE_INTERPRETER + #endif // !DACCESS_COMPILE #endif // __excep_h__ diff --git a/src/runtime/src/coreclr/vm/exceptionhandling.cpp b/src/runtime/src/coreclr/vm/exceptionhandling.cpp index 34307e039a8..b939ddc968c 100644 --- a/src/runtime/src/coreclr/vm/exceptionhandling.cpp +++ b/src/runtime/src/coreclr/vm/exceptionhandling.cpp @@ -534,7 +534,7 @@ static void PopExplicitFrames(Thread *pThread, void *targetSp, void *targetCalle if (popGCFrames) { GCFrame* pGCFrame = pThread->GetGCFrame(); - while (pGCFrame && pGCFrame < targetSp) + while ((pGCFrame != GCFRAME_TOP) && pGCFrame < targetSp) { pGCFrame->Pop(); pGCFrame = pThread->GetGCFrame(); @@ -3002,23 +3002,49 @@ extern "C" void QCALLTYPE AppendExceptionStackFrame(QCall::ObjectHandleOnStack e END_QCALL; } -#if defined(HOST_AMD64) && defined(HOST_WINDOWS) -size_t GetSSPForFrameOnCurrentStack(TADDR ip) +void ExecuteFunctionBelowContext(PCODE functionPtr, CONTEXT *pContext, size_t targetSSP, size_t arg1, size_t arg2) { - size_t *targetSSP = (size_t *)_rdsspq(); - // The SSP we search is pointing to the return address of the frame represented - // by the passed in IP. So we search for the instruction pointer from - // the context and return one slot up from there. - if (targetSSP != NULL) + UINT_PTR targetSp = GetSP(pContext); +#if defined(HOST_AMD64) + ULONG64* returnAddress = (ULONG64*)(targetSp - 8); + *returnAddress = pContext->Rip; +#ifdef HOST_WINDOWS + if (targetSSP != 0) { - while (*targetSSP++ != ip) - { - } + targetSSP -= sizeof(size_t); } +#endif // HOST_WINDOWS + SetSP(pContext, targetSp - 8); +#elif defined(HOST_X86) + +#ifdef HOST_WINDOWS + // Disarm the managed code SEH handler installed in CallDescrWorkerInternal + if (IsCallDescrWorkerInternalReturnAddress(pContext->Eip)) + { + PEXCEPTION_REGISTRATION_RECORD currentContext = GetCurrentSEHRecord(); + if (currentContext->Handler == (PEXCEPTION_ROUTINE)ProcessCLRException) + currentContext->Handler = (PEXCEPTION_ROUTINE)CallDescrWorkerUnwindFrameChainHandler; + } +#endif + + ULONG32* returnAddress = (ULONG32*)(targetSp - 4); + *returnAddress = pContext->Eip; + SetSP(pContext, targetSp - 4); +#elif defined(HOST_ARM64) + pContext->Lr = GetIP(pContext); +#elif defined(HOST_ARM) + pContext->Lr = GetIP(pContext); +#elif defined(HOST_RISCV64) || defined(HOST_LOONGARCH64) + pContext->Ra = GetIP(pContext); +#endif - return (size_t)targetSSP; + SetFirstArgReg(pContext, arg1); + SetSecondArgReg(pContext, arg2); + SetIP(pContext, functionPtr); + + ClrRestoreNonvolatileContext(pContext, targetSSP); + UNREACHABLE(); } -#endif // HOST_AMD64 && HOST_WINDOWS #ifdef HOST_WINDOWS VOID DECLSPEC_NORETURN PropagateLongJmpThroughNativeFrames(jmp_buf *pJmpBuf, int retVal) @@ -3073,15 +3099,24 @@ extern "C" void * QCALLTYPE CallCatchFunclet(QCall::ObjectHandleOnStack exceptio UINT_PTR callerTargetSp = 0; #if defined(HOST_AMD64) && defined(HOST_WINDOWS) size_t targetSSP = exInfo->m_frameIter.m_crawl.GetRegisterSet()->SSP; - _ASSERTE(targetSSP == 0 || (*(size_t*)(targetSSP-8) == exInfo->m_frameIter.m_crawl.GetRegisterSet()->ControlPC)); + // Verify the SSP points to the slot that matches the ControlPC of the frame containing the catch funclet. + // But don't check in case the target is in the interpreter loop, because the ControlPC doesn't match the shadow stack entry + // in that case. The shadow stack contains the return address of the DispatchManagedException call, but the ControlPC is the + // value captured to the exception context before the DispatchManagedException call. + _ASSERTE(targetSSP == 0 || + (pHandlerIP != NULL) && (exInfo->m_frameIter.m_crawl.GetCodeManager() == ExecutionManager::GetInterpreterCodeManager()) || + (*(size_t*)(targetSSP-8) == exInfo->m_frameIter.m_crawl.GetRegisterSet()->ControlPC)); #else size_t targetSSP = 0; #endif + ICodeManager* pCodeManager = NULL; + if (pHandlerIP != NULL) { + pCodeManager = exInfo->m_frameIter.m_crawl.GetCodeManager(); #ifdef _DEBUG - exInfo->m_frameIter.m_crawl.GetCodeManager()->EnsureCallerContextIsValid(pvRegDisplay); + pCodeManager->EnsureCallerContextIsValid(pvRegDisplay); _ASSERTE(exInfo->m_sfCallerOfActualHandlerFrame == GetSP(pvRegDisplay->pCallerContext)); #endif OBJECTREF throwable = exceptionObj.Get(); @@ -3096,7 +3131,7 @@ extern "C" void * QCALLTYPE CallCatchFunclet(QCall::ObjectHandleOnStack exceptio EH_LOG((LL_INFO100, "Calling catch funclet at %p\n", pHandlerIP)); - dwResumePC = exInfo->m_frameIter.m_crawl.GetCodeManager()->CallFunclet(throwable, pHandlerIP, pvRegDisplay, exInfo, false /* isFilterFunclet */); + dwResumePC = pCodeManager->CallFunclet(throwable, pHandlerIP, pvRegDisplay, exInfo, false /* isFilterFunclet */); FixContext(pvRegDisplay->pCurrentContext); @@ -3169,37 +3204,7 @@ extern "C" void * QCALLTYPE CallCatchFunclet(QCall::ObjectHandleOnStack exceptio ExInfo::UpdateNonvolatileRegisters(pvRegDisplay->pCurrentContext, pvRegDisplay, FALSE); if (pHandlerIP != NULL) { - UINT_PTR uAbortAddr = 0; - if (!fIntercepted) - { - CopyOSContext(pThread->m_OSContext, pvRegDisplay->pCurrentContext); - SetIP(pThread->m_OSContext, (PCODE)dwResumePC); - uAbortAddr = (UINT_PTR)COMPlusCheckForAbort(dwResumePC); - } - if (uAbortAddr) - { - STRESS_LOG2(LF_EH, LL_INFO10, "Thread abort in progress, resuming under control: IP=%p, SP=%p\n", dwResumePC, GetSP(pvRegDisplay->pCurrentContext)); -#ifdef TARGET_AMD64 -#ifdef TARGET_UNIX - pvRegDisplay->pCurrentContext->Rdi = dwResumePC; -#else - pvRegDisplay->pCurrentContext->Rcx = dwResumePC; -#endif -#elif defined(TARGET_ARM) || defined(TARGET_ARM64) - // On ARM & ARM64, we save off the original PC in Lr. This is the same as done - // in HandleManagedFault for H/W generated exceptions. - pvRegDisplay->pCurrentContext->Lr = dwResumePC; -#elif defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - pvRegDisplay->pCurrentContext->Ra = dwResumePC; -#endif - - SetIP(pvRegDisplay->pCurrentContext, uAbortAddr); - } - else - { - STRESS_LOG2(LF_EH, LL_INFO100, "Resuming after exception at IP=%p, SP=%p\n", GetIP(pvRegDisplay->pCurrentContext), GetSP(pvRegDisplay->pCurrentContext)); - } - ClrRestoreNonvolatileContext(pvRegDisplay->pCurrentContext, targetSSP); + pCodeManager->ResumeAfterCatch(pvRegDisplay->pCurrentContext, targetSSP, fIntercepted); } else { @@ -3243,75 +3248,19 @@ extern "C" void * QCALLTYPE CallCatchFunclet(QCall::ObjectHandleOnStack exceptio } #endif // HOST_WINDOWS -#if defined(HOST_AMD64) - ULONG64* returnAddress = (ULONG64*)(targetSp - 8); - *returnAddress = pvRegDisplay->pCurrentContext->Rip; -#ifdef HOST_WINDOWS - if (targetSSP != 0) - { - targetSSP -= sizeof(size_t); - } -#endif // HOST_WINDOWS - SetSP(pvRegDisplay->pCurrentContext, targetSp - 8); -#elif defined(HOST_X86) - -#ifdef HOST_WINDOWS - // Disarm the managed code SEH handler installed in CallDescrWorkerInternal - if (IsCallDescrWorkerInternalReturnAddress(pvRegDisplay->pCurrentContext->Eip)) - { - PEXCEPTION_REGISTRATION_RECORD currentContext = GetCurrentSEHRecord(); - if (currentContext->Handler == (PEXCEPTION_ROUTINE)ProcessCLRException) - currentContext->Handler = (PEXCEPTION_ROUTINE)CallDescrWorkerUnwindFrameChainHandler; - } -#endif - - ULONG32* returnAddress = (ULONG32*)(targetSp - 4); - *returnAddress = pvRegDisplay->pCurrentContext->Eip; - SetSP(pvRegDisplay->pCurrentContext, targetSp - 4); -#elif defined(HOST_ARM64) - pvRegDisplay->pCurrentContext->Lr = GetIP(pvRegDisplay->pCurrentContext); -#elif defined(HOST_ARM) - pvRegDisplay->pCurrentContext->Lr = GetIP(pvRegDisplay->pCurrentContext); -#elif defined(HOST_RISCV64) || defined(HOST_LOONGARCH64) - pvRegDisplay->pCurrentContext->Ra = GetIP(pvRegDisplay->pCurrentContext); -#endif - -// The SECOND_ARG_REG is defined only for Windows, it is used to handle longjmp propagation over managed frames -#ifdef HOST_AMD64 -#ifdef UNIX_AMD64_ABI -#define FIRST_ARG_REG Rdi -#else -#define FIRST_ARG_REG Rcx -#define SECOND_ARG_REG Rdx -#endif -#elif defined(HOST_X86) -#define FIRST_ARG_REG Ecx -#define SECOND_ARG_REG Edx -#elif defined(HOST_ARM64) -#define FIRST_ARG_REG X0 -#define SECOND_ARG_REG X1 -#elif defined(HOST_ARM) -#define FIRST_ARG_REG R0 -#elif defined(HOST_RISCV64) || defined(HOST_LOONGARCH64) -#define FIRST_ARG_REG A0 -#endif #ifdef HOST_WINDOWS if (pLongJmpBuf != NULL) { STRESS_LOG2(LF_EH, LL_INFO100, "Resuming propagation of longjmp through native frames at IP=%p, SP=%p\n", GetIP(pvRegDisplay->pCurrentContext), GetSP(pvRegDisplay->pCurrentContext)); - SetIP(pvRegDisplay->pCurrentContext, (PCODE)PropagateLongJmpThroughNativeFrames); - pvRegDisplay->pCurrentContext->FIRST_ARG_REG = (size_t)pLongJmpBuf; - pvRegDisplay->pCurrentContext->SECOND_ARG_REG = (size_t)longJmpReturnValue; + ExecuteFunctionBelowContext((PCODE)PropagateLongJmpThroughNativeFrames, pvRegDisplay->pCurrentContext, targetSSP, (size_t)pLongJmpBuf, longJmpReturnValue); } else #endif { STRESS_LOG2(LF_EH, LL_INFO100, "Resuming propagation of managed exception through native frames at IP=%p, SP=%p\n", GetIP(pvRegDisplay->pCurrentContext), GetSP(pvRegDisplay->pCurrentContext)); - SetIP(pvRegDisplay->pCurrentContext, (PCODE)(void (*)(Object*))PropagateExceptionThroughNativeFrames); - pvRegDisplay->pCurrentContext->FIRST_ARG_REG = (size_t)OBJECTREFToObject(exceptionObj.Get()); + ExecuteFunctionBelowContext((PCODE)PropagateExceptionThroughNativeFrames, pvRegDisplay->pCurrentContext, targetSSP, (size_t)OBJECTREFToObject(exceptionObj.Get())); } #undef FIRST_ARG_REG - ClrRestoreNonvolatileContext(pvRegDisplay->pCurrentContext, targetSSP); } END_QCALL; return NULL; @@ -3850,7 +3799,7 @@ extern "C" CLR_BOOL QCALLTYPE SfiInit(StackFrameIterator* pThis, CONTEXT* pStack // the SSP is already known. For other cases, find it by scanning the shadow stack. if ((pExInfo->m_passNumber == 2) && (pThis->m_crawl.GetRegisterSet()->SSP == 0)) { - pThis->m_crawl.GetRegisterSet()->SSP = GetSSPForFrameOnCurrentStack(controlPC); + pThis->m_crawl.GetCodeInfo()->GetCodeManager()->UpdateSSP(pThis->m_crawl.GetRegisterSet()); } #endif @@ -3930,6 +3879,21 @@ extern "C" CLR_BOOL QCALLTYPE SfiNext(StackFrameIterator* pThis, uint* uExCollid goto Exit; } +#ifdef FEATURE_INTERPRETER + if ((pThis->GetFrameState() == StackFrameIterator::SFITER_NATIVE_MARKER_FRAME) && (GetIP(pThis->m_crawl.GetRegisterSet()->pCurrentContext) == 0)) + { + // The callerIP is 0 when we are going to unwind from the first interpreted frame belonging to an InterpreterFrame. + // That means it is at a transition where non-interpreted code called interpreted one. + // Move the stack frame iterator to the InterpreterFrame and extract the IP of the real caller of the interpreted code. + retVal = pThis->Next(); + _ASSERTE(retVal != SWA_FAILED); + _ASSERTE(pThis->m_crawl.GetFrame()->GetFrameIdentifier() == FrameIdentifier::InterpreterFrame); + // Move to the caller of the interpreted code + retVal = pThis->Next(); + _ASSERTE(retVal != SWA_FAILED); + } +#endif // FEATURE_INTERPRETER + // Check for reverse pinvoke or CallDescrWorkerInternal. if (pThis->GetFrameState() == StackFrameIterator::SFITER_NATIVE_MARKER_FRAME) { diff --git a/src/runtime/src/coreclr/vm/exceptionhandling.h b/src/runtime/src/coreclr/vm/exceptionhandling.h index 35321dcef74..50edc30507d 100644 --- a/src/runtime/src/coreclr/vm/exceptionhandling.h +++ b/src/runtime/src/coreclr/vm/exceptionhandling.h @@ -64,6 +64,27 @@ enum class InlinedCallFrameMarker Mask = ExceptionHandlingHelper | SecondPassFuncletCaller }; +#ifdef FEATURE_INTERPRETER +class ResumeAfterCatchException +{ + TADDR m_resumeSP; + TADDR m_resumeIP; +public: + ResumeAfterCatchException(TADDR resumeSP, TADDR resumeIP) + : m_resumeSP(resumeSP), + m_resumeIP(resumeIP) + {} + + void GetResumeContext(TADDR * pResumeSP, TADDR * pResumeIP) const + { + *pResumeSP = m_resumeSP; + *pResumeIP = m_resumeIP; + } +}; +#endif // FEATURE_INTERPRETER + +void DECLSPEC_NORETURN ExecuteFunctionBelowContext(PCODE functionPtr, CONTEXT *pContext, size_t targetSSP, size_t arg1 = 0, size_t arg2 = 0); + #endif // FEATURE_EH_FUNCLETS #if defined(TARGET_X86) diff --git a/src/runtime/src/coreclr/vm/exceptmacros.h b/src/runtime/src/coreclr/vm/exceptmacros.h index db1de58e162..959d3263246 100644 --- a/src/runtime/src/coreclr/vm/exceptmacros.h +++ b/src/runtime/src/coreclr/vm/exceptmacros.h @@ -270,6 +270,10 @@ VOID DECLSPEC_NORETURN RaiseTheExceptionInternalOnly(OBJECTREF throwable, BOOL r void UnwindAndContinueRethrowHelperInsideCatch(Frame* pEntryFrame, Exception* pException); VOID DECLSPEC_NORETURN UnwindAndContinueRethrowHelperAfterCatch(Frame* pEntryFrame, Exception* pException, bool nativeRethrow); +#ifdef FEATURE_INTERPRETER +VOID DECLSPEC_NORETURN UnwindAndContinueResumeAfterCatch(TADDR resumeSP, TADDR resumeIP); +#endif // FEATURE_INTERPRETER + #ifdef TARGET_UNIX VOID DECLSPEC_NORETURN DispatchManagedException(PAL_SEHException& ex, bool isHardwareException); diff --git a/src/runtime/src/coreclr/vm/frames.cpp b/src/runtime/src/coreclr/vm/frames.cpp index 8a2d4605eaa..6f5a4833ba3 100644 --- a/src/runtime/src/coreclr/vm/frames.cpp +++ b/src/runtime/src/coreclr/vm/frames.cpp @@ -1136,19 +1136,25 @@ GCFrame::~GCFrame() } CONTRACTL_END; - // Do a manual switch to the GC cooperative mode instead of using the GCX_COOP_THREAD_EXISTS - // macro so that this function isn't slowed down by having to deal with FS:0 chain on x86 Windows. - BOOL wasCoop = m_pCurThread->PreemptiveGCDisabled(); - if (!wasCoop) + // m_pNext is NULL when the frame was already popped from the stack. + if (m_Next != NULL) { - m_pCurThread->DisablePreemptiveGC(); - } + // This is a GCFrame that was not popped. This is a problem. + // We should have popped it before we destruct + // Do a manual switch to the GC cooperative mode instead of using the GCX_COOP_THREAD_EXISTS + // macro so that this function isn't slowed down by having to deal with FS:0 chain on x86 Windows. + BOOL wasCoop = m_pCurThread->PreemptiveGCDisabled(); + if (!wasCoop) + { + m_pCurThread->DisablePreemptiveGC(); + } - Pop(); + Pop(); - if (!wasCoop) - { - m_pCurThread->EnablePreemptiveGC(); + if (!wasCoop) + { + m_pCurThread->EnablePreemptiveGC(); + } } } @@ -1174,7 +1180,7 @@ void GCFrame::Push(Thread* pThread) // in which the compiler will lay them out in the stack frame. // So GetOsPageSize() is a guess of the maximum stack frame size of any method // with multiple GCFrames in coreclr.dll - _ASSERTE(((m_Next == NULL) || + _ASSERTE(((m_Next == GCFRAME_TOP) || (PBYTE(m_Next) + (2 * GetOsPageSize())) > PBYTE(this)) && "Pushing a GCFrame out of order ?"); @@ -1221,7 +1227,7 @@ void GCFrame::Remove() GCFrame *pPrevFrame = NULL; GCFrame *pFrame = m_pCurThread->GetGCFrame(); - while (pFrame != NULL) + while (pFrame != GCFRAME_TOP) { if (pFrame == this) { @@ -1333,7 +1339,7 @@ BOOL IsProtectedByGCFrame(OBJECTREF *ppObjectRef) GetThread()->StackWalkFrames(IsProtectedByGCFrameStackWalkFramesCallback, &d); GCFrame* pGCFrame = GetThread()->GetGCFrame(); - while (pGCFrame != NULL) + while (pGCFrame != GCFRAME_TOP) { if (pGCFrame->Protects(ppObjectRef)) { d.count++; @@ -2132,6 +2138,40 @@ PTR_InterpMethodContextFrame InterpreterFrame::GetTopInterpMethodContextFrame() return pFrame; } +void InterpreterFrame::SetContextToInterpMethodContextFrame(T_CONTEXT * pContext) +{ + PTR_InterpMethodContextFrame pFrame = GetTopInterpMethodContextFrame(); + SetIP(pContext, (TADDR)pFrame->ip); + SetSP(pContext, dac_cast(pFrame)); + SetFP(pContext, (TADDR)pFrame->pStack); + SetFirstArgReg(pContext, (TADDR)this); +} + +void InterpreterFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats) +{ + SyncRegDisplayToCurrentContext(pRD); + TransitionFrame::UpdateRegDisplay_Impl(pRD, updateFloats); +} + +#ifndef DACCESS_COMPILE +void InterpreterFrame::ExceptionUnwind_Impl() +{ + WRAPPER_NO_CONTRACT; + + Thread *pThread = GetThread(); + InterpThreadContext *pThreadContext = pThread->GetInterpThreadContext(); + InterpMethodContextFrame *pInterpMethodContextFrame = m_pTopInterpMethodContextFrame; + + // Unwind the interpreter frames belonging to the current InterpreterFrame. + while (pInterpMethodContextFrame != NULL) + { + pThreadContext->frameDataAllocator.PopInfo(pInterpMethodContextFrame); + pThreadContext->pStackPointer = pInterpMethodContextFrame->pStack; + pInterpMethodContextFrame = pInterpMethodContextFrame->pParent; + } +} +#endif // !DACCESS_COMPILE + #endif // FEATURE_INTERPRETER #ifndef DACCESS_COMPILE diff --git a/src/runtime/src/coreclr/vm/frames.h b/src/runtime/src/coreclr/vm/frames.h index 6444b6ee776..9636dd9ee73 100644 --- a/src/runtime/src/coreclr/vm/frames.h +++ b/src/runtime/src/coreclr/vm/frames.h @@ -220,6 +220,7 @@ class ComCallMethodDesc; // whenever we compare it to a PTR_Frame value (the usual use of the value). #define FRAME_TOP_VALUE ~0 // we want to say -1 here, but gcc has trouble with the signed value #define FRAME_TOP (PTR_Frame(FRAME_TOP_VALUE)) +#define GCFRAME_TOP (PTR_GCFrame(FRAME_TOP_VALUE)) enum class FrameIdentifier : TADDR @@ -1034,8 +1035,6 @@ struct cdac_data #endif // FEATURE_EH_FUNCLETS }; -#ifdef FEATURE_EH_FUNCLETS - typedef DPTR(class SoftwareExceptionFrame) PTR_SoftwareExceptionFrame; class SoftwareExceptionFrame : public Frame @@ -1107,7 +1106,6 @@ struct cdac_data static constexpr size_t TargetContext = offsetof(SoftwareExceptionFrame, m_Context); static constexpr size_t ReturnAddress = offsetof(SoftwareExceptionFrame, m_ReturnAddress); }; -#endif // FEATURE_EH_FUNCLETS //----------------------------------------------------------------------- // Frame for debugger function evaluation @@ -2889,6 +2887,9 @@ class InterpreterFrame : public FramedMethodFrame InterpreterFrame(TransitionBlock* pTransitionBlock, InterpMethodContextFrame* pContextFrame) : FramedMethodFrame(FrameIdentifier::InterpreterFrame, pTransitionBlock, NULL), m_pTopInterpMethodContextFrame(pContextFrame) +#if defined(HOST_AMD64) && defined(HOST_WINDOWS) + , m_SSP(0) +#endif { WRAPPER_NO_CONTRACT; Push(); @@ -2900,13 +2901,53 @@ class InterpreterFrame : public FramedMethodFrame } #endif // DACCESS_COMPILE + + BOOL NeedsUpdateRegDisplay_Impl() + { + LIMITED_METHOD_CONTRACT; + return GetTransitionBlock() != 0; + } + + PCODE GetReturnAddressPtr_Impl() + { + WRAPPER_NO_CONTRACT; + if (GetTransitionBlock() == 0) + return 0; + + return FramedMethodFrame::GetReturnAddressPtr_Impl(); + } + + void UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats = false); +#ifndef DACCESS_COMPILE + void ExceptionUnwind_Impl(); +#endif + PTR_InterpMethodContextFrame GetTopInterpMethodContextFrame(); + void SetContextToInterpMethodContextFrame(T_CONTEXT * pContext); + +#if defined(HOST_AMD64) && defined(HOST_WINDOWS) + void SetInterpExecMethodSSP(TADDR ssp) + { + LIMITED_METHOD_CONTRACT; + m_SSP = ssp; + } + + TADDR GetInterpExecMethodSSP() + { + LIMITED_METHOD_CONTRACT; + return m_SSP; + } +#endif // HOST_AMD64 && HOST_WINDOWS + private: // The last known topmost interpreter frame in the InterpExecMethod belonging to // this InterpreterFrame. PTR_InterpMethodContextFrame m_pTopInterpMethodContextFrame; - +#if defined(HOST_AMD64) && defined(HOST_WINDOWS) + // Saved SSP of the InterpExecMethod for resuming after catch into interpreter frames. + TADDR m_SSP; +#endif // HOST_AMD64 && HOST_WINDOWS }; #endif // FEATURE_INTERPRETER diff --git a/src/runtime/src/coreclr/vm/gcenv.ee.cpp b/src/runtime/src/coreclr/vm/gcenv.ee.cpp index 4738b0d7aeb..6482ee4886f 100644 --- a/src/runtime/src/coreclr/vm/gcenv.ee.cpp +++ b/src/runtime/src/coreclr/vm/gcenv.ee.cpp @@ -207,7 +207,7 @@ static void ScanStackRoots(Thread * pThread, promote_func* fn, ScanContext* sc) } GCFrame* pGCFrame = pThread->GetGCFrame(); - while (pGCFrame != NULL) + while (pGCFrame != GCFRAME_TOP) { pGCFrame->GcScanRoots(fn, sc); pGCFrame = pGCFrame->PtrNextFrame(); diff --git a/src/runtime/src/coreclr/vm/gcheaputilities.h b/src/runtime/src/coreclr/vm/gcheaputilities.h index 8b40521c237..3a6aec2faab 100644 --- a/src/runtime/src/coreclr/vm/gcheaputilities.h +++ b/src/runtime/src/coreclr/vm/gcheaputilities.h @@ -250,7 +250,11 @@ class GCHeapUtilities { static bool UseThreadAllocationContexts() { +#if (defined(TARGET_X86) || defined(TARGET_AMD64)) && !defined(TARGET_UNIX) return s_useThreadAllocationContexts; +#else + return true; +#endif } #ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP diff --git a/src/runtime/src/coreclr/vm/i386/asmhelpers.asm b/src/runtime/src/coreclr/vm/i386/asmhelpers.asm index df93ca0be0a..740b3de93a7 100644 --- a/src/runtime/src/coreclr/vm/i386/asmhelpers.asm +++ b/src/runtime/src/coreclr/vm/i386/asmhelpers.asm @@ -90,11 +90,9 @@ EXTERN g_chained_lookup_miss_counter:DWORD EXTERN g_dispatch_cache_chain_success_counter:DWORD endif -ifdef FEATURE_EH_FUNCLETS EXTERN @IL_Throw_x86@8:PROC EXTERN @IL_ThrowExact_x86@8:PROC EXTERN @IL_Rethrow_x86@4:PROC -endif ; FEATURE_EH_FUNCLETS UNREFERENCED macro arg local unref @@ -1894,7 +1892,6 @@ _BackPatchWorkerAsmStub@0 proc public ret _BackPatchWorkerAsmStub@0 endp -ifdef FEATURE_EH_FUNCLETS ;========================================================================== ; Capture a transition block with register values and call the IL_Throw ; implementation written in C. @@ -1942,6 +1939,5 @@ FASTCALL_FUNC IL_Rethrow, 0 STUB_EPILOG ret 4 FASTCALL_ENDFUNC IL_Rethrow -endif ; FEATURE_EH_FUNCLETS end diff --git a/src/runtime/src/coreclr/vm/i386/cgencpu.h b/src/runtime/src/coreclr/vm/i386/cgencpu.h index 86fda62df15..1a9d9145d8a 100644 --- a/src/runtime/src/coreclr/vm/i386/cgencpu.h +++ b/src/runtime/src/coreclr/vm/i386/cgencpu.h @@ -231,6 +231,30 @@ inline TADDR GetFP(const CONTEXT * context) return (TADDR)context->Ebp; } +inline void SetFirstArgReg(CONTEXT *context, TADDR value) +{ + LIMITED_METHOD_DAC_CONTRACT; + context->Ecx = (DWORD)value; +} + +inline TADDR GetFirstArgReg(CONTEXT *context) +{ + LIMITED_METHOD_DAC_CONTRACT; + return (TADDR)(context->Ecx); +} + +inline void SetSecondArgReg(CONTEXT *context, TADDR value) +{ + LIMITED_METHOD_DAC_CONTRACT; + context->Edx = (DWORD)value; +} + +inline TADDR GetSecondArgReg(CONTEXT *context) +{ + LIMITED_METHOD_DAC_CONTRACT; + return (TADDR)(context->Edx); +} + // Get Rel32 destination, emit jumpStub if necessary inline INT32 rel32UsingJumpStub(INT32 UNALIGNED * pRel32, PCODE target, MethodDesc *pMethod = NULL, LoaderAllocator *pLoaderAllocator = NULL) { diff --git a/src/runtime/src/coreclr/vm/i386/jitinterfacex86.cpp b/src/runtime/src/coreclr/vm/i386/jitinterfacex86.cpp index 63d603e7225..ee59b847cf6 100644 --- a/src/runtime/src/coreclr/vm/i386/jitinterfacex86.cpp +++ b/src/runtime/src/coreclr/vm/i386/jitinterfacex86.cpp @@ -371,138 +371,6 @@ void *JIT_TrialAlloc::GenAllocSFast(Flags flags) return (void *)pStub->GetEntryPoint(); } - -void *JIT_TrialAlloc::GenBox(Flags flags) -{ - STANDARD_VM_CONTRACT; - - CPUSTUBLINKER sl; - - CodeLabel *noLock = sl.NewCodeLabel(); - CodeLabel *noAlloc = sl.NewCodeLabel(); - CodeLabel *nullRef = sl.NewCodeLabel(); - - // Save address of value to be boxed - sl.X86EmitPushReg(kEBX); - sl.Emit16(0xda8b); - - // Check for null ref - // test edx, edx - sl.X86EmitR2ROp(0x85, kEDX, kEDX); - - // je nullRef - sl.X86EmitCondJump(nullRef, X86CondCode::kJE); - - // Emit the main body of the trial allocator - EmitCore(&sl, noLock, noAlloc, flags); - - // Here we are at the end of the success case - - // Check whether the object contains pointers - // test [ecx]MethodTable.m_dwFlags,MethodTable::enum_flag_ContainsGCPointers - sl.X86EmitOffsetModRM(0xf7, (X86Reg)0x0, kECX, offsetof(MethodTable, m_dwFlags)); - sl.Emit32(MethodTable::enum_flag_ContainsGCPointers); - - CodeLabel *pointerLabel = sl.NewCodeLabel(); - - // jne pointerLabel - sl.X86EmitCondJump(pointerLabel, X86CondCode::kJNE); - - // We have no pointers - emit a simple inline copy loop - - // mov ecx, [ecx]MethodTable.m_BaseSize - sl.X86EmitOffsetModRM(0x8b, kECX, kECX, offsetof(MethodTable, m_BaseSize)); - - // sub ecx,12 - sl.X86EmitSubReg(kECX, 12); - - CodeLabel *loopLabel = sl.NewCodeLabel(); - - sl.EmitLabel(loopLabel); - - // mov edx,[ebx+ecx] - sl.X86EmitOp(0x8b, kEDX, kEBX, 0, kECX, 1); - - // mov [eax+ecx+4],edx - sl.X86EmitOp(0x89, kEDX, kEAX, 4, kECX, 1); - - // sub ecx,4 - sl.X86EmitSubReg(kECX, 4); - - // jg loopLabel - sl.X86EmitCondJump(loopLabel, X86CondCode::kJGE); - - sl.X86EmitPopReg(kEBX); - - sl.X86EmitReturn(0); - - // Arrive at this label if there are pointers in the object - sl.EmitLabel(pointerLabel); - - // Do call to CopyValueClassUnchecked(object, data, pMT) - -#ifdef UNIX_X86_ABI -#define STACK_ALIGN_PADDING 12 - // Make pad to align esp - sl.X86EmitSubEsp(STACK_ALIGN_PADDING); -#endif // UNIX_X86_ABI - - // Pass pMT (still in ECX) - sl.X86EmitPushReg(kECX); - - // Pass data (still in EBX) - sl.X86EmitPushReg(kEBX); - - // Save the address of the object just allocated - // mov ebx,eax - sl.Emit16(0xD88B); - - - // Pass address of first user byte in the newly allocated object - sl.X86EmitAddReg(kEAX, 4); - sl.X86EmitPushReg(kEAX); - - // call CopyValueClass - sl.X86EmitCall(sl.NewExternalCodeLabel((LPVOID) CopyValueClassUnchecked), 12); -#ifdef UNIX_X86_ABI - // Make pad to align esp - sl.X86EmitAddEsp(STACK_ALIGN_PADDING); -#undef STACK_ALIGN_PADDING -#endif // UNIX_X86_ABI - - // Restore the address of the newly allocated object and return it. - // mov eax,ebx - sl.Emit16(0xC38B); - - sl.X86EmitPopReg(kEBX); - - sl.X86EmitReturn(0); - - // Come here in case of no space or null ref - sl.EmitLabel(noAlloc); - sl.EmitLabel(nullRef); - - // Release the lock in the uniprocessor case - EmitNoAllocCode(&sl, flags); - - // Come here in case of failure to get the lock - sl.EmitLabel(noLock); - - // Restore the address of the value to be boxed - // mov edx,ebx - sl.Emit16(0xD38B); - - // pop ebx - sl.X86EmitPopReg(kEBX); - - // Jump to the slow version of JIT_Box - sl.X86EmitNearJump(sl.NewExternalCodeLabel((LPVOID) JIT_Box)); - - Stub *pStub = sl.Link(SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap(), NEWSTUB_FL_NONE, "Box"); - - return (void *)pStub->GetEntryPoint(); -} - void *JIT_TrialAlloc::GenAllocArray(Flags flags) { STANDARD_VM_CONTRACT; @@ -793,7 +661,6 @@ void InitJITHelpers1() static const LPCWSTR pHelperNames[ETW_NUM_JIT_HELPERS] = { W("@NewObject"), W("@NewObjectAlign8"), - W("@Box"), W("@NewArray1Object"), W("@NewArray1ValueType"), W("@NewArray1ObjectAlign8"), @@ -824,14 +691,12 @@ void InitJITHelpers1() SetJitHelperFunction(CORINFO_HELP_NEWSFAST, pMethodAddresses[0]); pMethodAddresses[1] = JIT_TrialAlloc::GenAllocSFast((JIT_TrialAlloc::Flags)(flags|JIT_TrialAlloc::ALIGN8 | JIT_TrialAlloc::ALIGN8OBJ)); SetJitHelperFunction(CORINFO_HELP_NEWSFAST_ALIGN8, pMethodAddresses[1]); - pMethodAddresses[2] = JIT_TrialAlloc::GenBox(flags); - SetJitHelperFunction(CORINFO_HELP_BOX, pMethodAddresses[2]); - pMethodAddresses[3] = JIT_TrialAlloc::GenAllocArray((JIT_TrialAlloc::Flags)(flags|JIT_TrialAlloc::OBJ_ARRAY)); - SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, pMethodAddresses[3]); - pMethodAddresses[4] = JIT_TrialAlloc::GenAllocArray(flags); - SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, pMethodAddresses[4]); - pMethodAddresses[5] = JIT_TrialAlloc::GenAllocArray((JIT_TrialAlloc::Flags)(flags|JIT_TrialAlloc::ALIGN8)); - SetJitHelperFunction(CORINFO_HELP_NEWARR_1_ALIGN8, pMethodAddresses[5]); + pMethodAddresses[2] = JIT_TrialAlloc::GenAllocArray((JIT_TrialAlloc::Flags)(flags|JIT_TrialAlloc::OBJ_ARRAY)); + SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, pMethodAddresses[2]); + pMethodAddresses[3] = JIT_TrialAlloc::GenAllocArray(flags); + SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, pMethodAddresses[3]); + pMethodAddresses[4] = JIT_TrialAlloc::GenAllocArray((JIT_TrialAlloc::Flags)(flags|JIT_TrialAlloc::ALIGN8)); + SetJitHelperFunction(CORINFO_HELP_NEWARR_1_ALIGN8, pMethodAddresses[4]); // If allocation logging is on, then we divert calls to FastAllocateString to an Ecall method, not this // generated method. Find this workaround in Ecall::Init() in ecall.cpp. diff --git a/src/runtime/src/coreclr/vm/interpexec.cpp b/src/runtime/src/coreclr/vm/interpexec.cpp index 78e0e1fe667..c01008f89ee 100644 --- a/src/runtime/src/coreclr/vm/interpexec.cpp +++ b/src/runtime/src/coreclr/vm/interpexec.cpp @@ -35,6 +35,10 @@ static void InterpBreakpoint() void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFrame *pFrame, InterpThreadContext *pThreadContext) { +#if defined(HOST_AMD64) && defined(HOST_WINDOWS) + pInterpreterFrame->SetInterpExecMethodSSP((TADDR)_rdsspq()); +#endif // HOST_AMD64 && HOST_WINDOWS + const int32_t *ip; int8_t *stack; @@ -47,246 +51,250 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr const int32_t *targetIp; MAIN_LOOP: - while (true) + try { - // Interpreter-TODO: This is only needed to enable SOS see the exact location in the interpreted method. - // Neither the GC nor the managed debugger needs that as they walk the stack when the runtime is suspended - // and we can save the IP to the frame at the suspension time. - // It will be useful for testing e.g. the debug info at various locations in the current method, so let's - // keep it for such purposes until we don't need it anymore. - pFrame->ip = (int32_t*)ip; - - switch (*ip) + INSTALL_MANAGED_EXCEPTION_DISPATCHER; + INSTALL_UNWIND_AND_CONTINUE_HANDLER; + while (true) { + // Interpreter-TODO: This is only needed to enable SOS see the exact location in the interpreted method. + // Neither the GC nor the managed debugger needs that as they walk the stack when the runtime is suspended + // and we can save the IP to the frame at the suspension time. + // It will be useful for testing e.g. the debug info at various locations in the current method, so let's + // keep it for such purposes until we don't need it anymore. + pFrame->ip = (int32_t*)ip; + + switch (*ip) + { #ifdef DEBUG - case INTOP_BREAKPOINT: - InterpBreakpoint(); - ip++; - break; + case INTOP_BREAKPOINT: + InterpBreakpoint(); + ip++; + break; #endif - case INTOP_INITLOCALS: - memset(stack + ip[1], 0, ip[2]); - ip += 3; - break; - case INTOP_MEMBAR: - MemoryBarrier(); - ip++; - break; - case INTOP_LDC_I4: - LOCAL_VAR(ip[1], int32_t) = ip[2]; - ip += 3; - break; - case INTOP_LDC_I4_0: - LOCAL_VAR(ip[1], int32_t) = 0; - ip += 2; - break; - case INTOP_LDC_I8_0: - LOCAL_VAR(ip[1], int64_t) = 0; - ip += 2; - break; - case INTOP_LDC_I8: - LOCAL_VAR(ip[1], int64_t) = (int64_t)ip[2] + ((int64_t)ip[3] << 32); - ip += 4; - break; - case INTOP_LDC_R4: - LOCAL_VAR(ip[1], int32_t) = ip[2]; - ip += 3; - break; - case INTOP_LDC_R8: - LOCAL_VAR(ip[1], int64_t) = (int64_t)ip[2] + ((int64_t)ip[3] << 32); - ip += 4; - break; - case INTOP_LDPTR: - LOCAL_VAR(ip[1], void*) = pMethod->pDataItems[ip[2]]; - ip += 3; - break; - case INTOP_RET: - // Return stack slot sized value - *(int64_t*)pFrame->pRetVal = LOCAL_VAR(ip[1], int64_t); - goto EXIT_FRAME; - case INTOP_RET_VT: - memmove(pFrame->pRetVal, stack + ip[1], ip[2]); - goto EXIT_FRAME; - case INTOP_RET_VOID: - goto EXIT_FRAME; - - case INTOP_LDLOCA: - LOCAL_VAR(ip[1], void*) = stack + ip[2]; - ip += 3; - break;; + case INTOP_INITLOCALS: + memset(stack + ip[1], 0, ip[2]); + ip += 3; + break; + case INTOP_MEMBAR: + MemoryBarrier(); + ip++; + break; + case INTOP_LDC_I4: + LOCAL_VAR(ip[1], int32_t) = ip[2]; + ip += 3; + break; + case INTOP_LDC_I4_0: + LOCAL_VAR(ip[1], int32_t) = 0; + ip += 2; + break; + case INTOP_LDC_I8_0: + LOCAL_VAR(ip[1], int64_t) = 0; + ip += 2; + break; + case INTOP_LDC_I8: + LOCAL_VAR(ip[1], int64_t) = (int64_t)ip[2] + ((int64_t)ip[3] << 32); + ip += 4; + break; + case INTOP_LDC_R4: + LOCAL_VAR(ip[1], int32_t) = ip[2]; + ip += 3; + break; + case INTOP_LDC_R8: + LOCAL_VAR(ip[1], int64_t) = (int64_t)ip[2] + ((int64_t)ip[3] << 32); + ip += 4; + break; + case INTOP_LDPTR: + LOCAL_VAR(ip[1], void*) = pMethod->pDataItems[ip[2]]; + ip += 3; + break; + case INTOP_RET: + // Return stack slot sized value + *(int64_t*)pFrame->pRetVal = LOCAL_VAR(ip[1], int64_t); + goto EXIT_FRAME; + case INTOP_RET_VT: + memmove(pFrame->pRetVal, stack + ip[1], ip[2]); + goto EXIT_FRAME; + case INTOP_RET_VOID: + goto EXIT_FRAME; + + case INTOP_LDLOCA: + LOCAL_VAR(ip[1], void*) = stack + ip[2]; + ip += 3; + break;; #define MOV(argtype1,argtype2) \ LOCAL_VAR(ip [1], argtype1) = LOCAL_VAR(ip [2], argtype2); \ ip += 3; - // When loading from a local, we might need to sign / zero extend to 4 bytes - // which is our minimum "register" size in interp. They are only needed when - // the address of the local is taken and we should try to optimize them out - // because the local can't be propagated. - case INTOP_MOV_I4_I1: MOV(int32_t, int8_t); break; - case INTOP_MOV_I4_U1: MOV(int32_t, uint8_t); break; - case INTOP_MOV_I4_I2: MOV(int32_t, int16_t); break; - case INTOP_MOV_I4_U2: MOV(int32_t, uint16_t); break; - // Normal moves between vars - case INTOP_MOV_4: MOV(int32_t, int32_t); break; - case INTOP_MOV_8: MOV(int64_t, int64_t); break; - - case INTOP_MOV_VT: - memmove(stack + ip[1], stack + ip[2], ip[3]); - ip += 4; - break; - - case INTOP_CONV_R_UN_I4: - LOCAL_VAR(ip[1], double) = (double)LOCAL_VAR(ip[2], uint32_t); - ip += 3; - break; - case INTOP_CONV_R_UN_I8: - LOCAL_VAR(ip[1], double) = (double)LOCAL_VAR(ip[2], uint64_t); - ip += 3; - break; - case INTOP_CONV_I1_I4: - LOCAL_VAR(ip[1], int32_t) = (int8_t)LOCAL_VAR(ip[2], int32_t); - ip += 3; - break; - case INTOP_CONV_I1_I8: - LOCAL_VAR(ip[1], int32_t) = (int8_t)LOCAL_VAR(ip[2], int64_t); - ip += 3; - break; - case INTOP_CONV_I1_R4: - LOCAL_VAR(ip[1], int32_t) = (int8_t)(int32_t)LOCAL_VAR(ip[2], float); - ip += 3; - break; - case INTOP_CONV_I1_R8: - LOCAL_VAR(ip[1], int32_t) = (int8_t)(int32_t)LOCAL_VAR(ip[2], double); - ip += 3; - break; - case INTOP_CONV_U1_I4: - LOCAL_VAR(ip[1], int32_t) = (uint8_t)LOCAL_VAR(ip[2], int32_t); - ip += 3; - break; - case INTOP_CONV_U1_I8: - LOCAL_VAR(ip[1], int32_t) = (uint8_t)LOCAL_VAR(ip[2], int64_t); - ip += 3; - break; - case INTOP_CONV_U1_R4: - LOCAL_VAR(ip[1], int32_t) = (uint8_t)(uint32_t)LOCAL_VAR(ip[2], float); - ip += 3; - break; - case INTOP_CONV_U1_R8: - LOCAL_VAR(ip[1], int32_t) = (uint8_t)(uint32_t)LOCAL_VAR(ip[2], double); - ip += 3; - break; - case INTOP_CONV_I2_I4: - LOCAL_VAR(ip[1], int32_t) = (int16_t)LOCAL_VAR(ip[2], int32_t); - ip += 3; - break; - case INTOP_CONV_I2_I8: - LOCAL_VAR(ip[1], int32_t) = (int16_t)LOCAL_VAR(ip[2], int64_t); - ip += 3; - break; - case INTOP_CONV_I2_R4: - LOCAL_VAR(ip[1], int32_t) = (int16_t)(int32_t)LOCAL_VAR(ip[2], float); - ip += 3; - break; - case INTOP_CONV_I2_R8: - LOCAL_VAR(ip[1], int32_t) = (int16_t)(int32_t)LOCAL_VAR(ip[2], double); - ip += 3; - break; - case INTOP_CONV_U2_I4: - LOCAL_VAR(ip[1], int32_t) = (uint16_t)LOCAL_VAR(ip[2], int32_t); - ip += 3; - break; - case INTOP_CONV_U2_I8: - LOCAL_VAR(ip[1], int32_t) = (uint16_t)LOCAL_VAR(ip[2], int64_t); - ip += 3; - break; - case INTOP_CONV_U2_R4: - LOCAL_VAR(ip[1], int32_t) = (uint16_t)(uint32_t)LOCAL_VAR(ip[2], float); - ip += 3; - break; - case INTOP_CONV_U2_R8: - LOCAL_VAR(ip[1], int32_t) = (uint16_t)(uint32_t)LOCAL_VAR(ip[2], double); - ip += 3; - break; - case INTOP_CONV_I4_R4: - LOCAL_VAR(ip[1], int32_t) = (int32_t)LOCAL_VAR(ip[2], float); - ip += 3; - break;; - case INTOP_CONV_I4_R8: - LOCAL_VAR(ip[1], int32_t) = (int32_t)LOCAL_VAR(ip[2], double); - ip += 3; - break;; - - case INTOP_CONV_U4_R4: - case INTOP_CONV_U4_R8: - assert(0); - break; - - case INTOP_CONV_I8_I4: - LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int32_t); - ip += 3; - break; - case INTOP_CONV_I8_U4: - LOCAL_VAR(ip[1], int64_t) = (uint32_t)LOCAL_VAR(ip[2], int32_t); - ip += 3; - break;; - case INTOP_CONV_I8_R4: - LOCAL_VAR(ip[1], int64_t) = (int64_t)LOCAL_VAR(ip[2], float); - ip += 3; - break; - case INTOP_CONV_I8_R8: - LOCAL_VAR(ip[1], int64_t) = (int64_t)LOCAL_VAR(ip[2], double); - ip += 3; - break; - case INTOP_CONV_R4_I4: - LOCAL_VAR(ip[1], float) = (float)LOCAL_VAR(ip[2], int32_t); - ip += 3; - break;; - case INTOP_CONV_R4_I8: - LOCAL_VAR(ip[1], float) = (float)LOCAL_VAR(ip[2], int64_t); - ip += 3; - break; - case INTOP_CONV_R4_R8: - LOCAL_VAR(ip[1], float) = (float)LOCAL_VAR(ip[2], double); - ip += 3; - break; - case INTOP_CONV_R8_I4: - LOCAL_VAR(ip[1], double) = (double)LOCAL_VAR(ip[2], int32_t); - ip += 3; - break; - case INTOP_CONV_R8_I8: - LOCAL_VAR(ip[1], double) = (double)LOCAL_VAR(ip[2], int64_t); - ip += 3; - break; - case INTOP_CONV_R8_R4: - LOCAL_VAR(ip[1], double) = (double)LOCAL_VAR(ip[2], float); - ip += 3; - break; - case INTOP_CONV_U8_R4: - case INTOP_CONV_U8_R8: - // TODO - assert(0); - break; - - case INTOP_SWITCH: - { - uint32_t val = LOCAL_VAR(ip[1], uint32_t); - uint32_t n = ip[2]; - ip += 3; - if (val < n) + // When loading from a local, we might need to sign / zero extend to 4 bytes + // which is our minimum "register" size in interp. They are only needed when + // the address of the local is taken and we should try to optimize them out + // because the local can't be propagated. + case INTOP_MOV_I4_I1: MOV(int32_t, int8_t); break; + case INTOP_MOV_I4_U1: MOV(int32_t, uint8_t); break; + case INTOP_MOV_I4_I2: MOV(int32_t, int16_t); break; + case INTOP_MOV_I4_U2: MOV(int32_t, uint16_t); break; + // Normal moves between vars + case INTOP_MOV_4: MOV(int32_t, int32_t); break; + case INTOP_MOV_8: MOV(int64_t, int64_t); break; + + case INTOP_MOV_VT: + memmove(stack + ip[1], stack + ip[2], ip[3]); + ip += 4; + break; + + case INTOP_CONV_R_UN_I4: + LOCAL_VAR(ip[1], double) = (double)LOCAL_VAR(ip[2], uint32_t); + ip += 3; + break; + case INTOP_CONV_R_UN_I8: + LOCAL_VAR(ip[1], double) = (double)LOCAL_VAR(ip[2], uint64_t); + ip += 3; + break; + case INTOP_CONV_I1_I4: + LOCAL_VAR(ip[1], int32_t) = (int8_t)LOCAL_VAR(ip[2], int32_t); + ip += 3; + break; + case INTOP_CONV_I1_I8: + LOCAL_VAR(ip[1], int32_t) = (int8_t)LOCAL_VAR(ip[2], int64_t); + ip += 3; + break; + case INTOP_CONV_I1_R4: + LOCAL_VAR(ip[1], int32_t) = (int8_t)(int32_t)LOCAL_VAR(ip[2], float); + ip += 3; + break; + case INTOP_CONV_I1_R8: + LOCAL_VAR(ip[1], int32_t) = (int8_t)(int32_t)LOCAL_VAR(ip[2], double); + ip += 3; + break; + case INTOP_CONV_U1_I4: + LOCAL_VAR(ip[1], int32_t) = (uint8_t)LOCAL_VAR(ip[2], int32_t); + ip += 3; + break; + case INTOP_CONV_U1_I8: + LOCAL_VAR(ip[1], int32_t) = (uint8_t)LOCAL_VAR(ip[2], int64_t); + ip += 3; + break; + case INTOP_CONV_U1_R4: + LOCAL_VAR(ip[1], int32_t) = (uint8_t)(uint32_t)LOCAL_VAR(ip[2], float); + ip += 3; + break; + case INTOP_CONV_U1_R8: + LOCAL_VAR(ip[1], int32_t) = (uint8_t)(uint32_t)LOCAL_VAR(ip[2], double); + ip += 3; + break; + case INTOP_CONV_I2_I4: + LOCAL_VAR(ip[1], int32_t) = (int16_t)LOCAL_VAR(ip[2], int32_t); + ip += 3; + break; + case INTOP_CONV_I2_I8: + LOCAL_VAR(ip[1], int32_t) = (int16_t)LOCAL_VAR(ip[2], int64_t); + ip += 3; + break; + case INTOP_CONV_I2_R4: + LOCAL_VAR(ip[1], int32_t) = (int16_t)(int32_t)LOCAL_VAR(ip[2], float); + ip += 3; + break; + case INTOP_CONV_I2_R8: + LOCAL_VAR(ip[1], int32_t) = (int16_t)(int32_t)LOCAL_VAR(ip[2], double); + ip += 3; + break; + case INTOP_CONV_U2_I4: + LOCAL_VAR(ip[1], int32_t) = (uint16_t)LOCAL_VAR(ip[2], int32_t); + ip += 3; + break; + case INTOP_CONV_U2_I8: + LOCAL_VAR(ip[1], int32_t) = (uint16_t)LOCAL_VAR(ip[2], int64_t); + ip += 3; + break; + case INTOP_CONV_U2_R4: + LOCAL_VAR(ip[1], int32_t) = (uint16_t)(uint32_t)LOCAL_VAR(ip[2], float); + ip += 3; + break; + case INTOP_CONV_U2_R8: + LOCAL_VAR(ip[1], int32_t) = (uint16_t)(uint32_t)LOCAL_VAR(ip[2], double); + ip += 3; + break; + case INTOP_CONV_I4_R4: + LOCAL_VAR(ip[1], int32_t) = (int32_t)LOCAL_VAR(ip[2], float); + ip += 3; + break;; + case INTOP_CONV_I4_R8: + LOCAL_VAR(ip[1], int32_t) = (int32_t)LOCAL_VAR(ip[2], double); + ip += 3; + break;; + + case INTOP_CONV_U4_R4: + case INTOP_CONV_U4_R8: + assert(0); + break; + + case INTOP_CONV_I8_I4: + LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int32_t); + ip += 3; + break; + case INTOP_CONV_I8_U4: + LOCAL_VAR(ip[1], int64_t) = (uint32_t)LOCAL_VAR(ip[2], int32_t); + ip += 3; + break;; + case INTOP_CONV_I8_R4: + LOCAL_VAR(ip[1], int64_t) = (int64_t)LOCAL_VAR(ip[2], float); + ip += 3; + break; + case INTOP_CONV_I8_R8: + LOCAL_VAR(ip[1], int64_t) = (int64_t)LOCAL_VAR(ip[2], double); + ip += 3; + break; + case INTOP_CONV_R4_I4: + LOCAL_VAR(ip[1], float) = (float)LOCAL_VAR(ip[2], int32_t); + ip += 3; + break;; + case INTOP_CONV_R4_I8: + LOCAL_VAR(ip[1], float) = (float)LOCAL_VAR(ip[2], int64_t); + ip += 3; + break; + case INTOP_CONV_R4_R8: + LOCAL_VAR(ip[1], float) = (float)LOCAL_VAR(ip[2], double); + ip += 3; + break; + case INTOP_CONV_R8_I4: + LOCAL_VAR(ip[1], double) = (double)LOCAL_VAR(ip[2], int32_t); + ip += 3; + break; + case INTOP_CONV_R8_I8: + LOCAL_VAR(ip[1], double) = (double)LOCAL_VAR(ip[2], int64_t); + ip += 3; + break; + case INTOP_CONV_R8_R4: + LOCAL_VAR(ip[1], double) = (double)LOCAL_VAR(ip[2], float); + ip += 3; + break; + case INTOP_CONV_U8_R4: + case INTOP_CONV_U8_R8: + // TODO + assert(0); + break; + + case INTOP_SWITCH: { - ip += val; - ip += *ip; - } - else - { - ip += n; + uint32_t val = LOCAL_VAR(ip[1], uint32_t); + uint32_t n = ip[2]; + ip += 3; + if (val < n) + { + ip += val; + ip += *ip; + } + else + { + ip += n; + } + break; } - break; - } - case INTOP_BR: - ip += ip[1]; - break; + case INTOP_BR: + ip += ip[1]; + break; #define BR_UNOP(datatype, op) \ if (LOCAL_VAR(ip[1], datatype) op) \ @@ -294,18 +302,18 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr else \ ip += 3; - case INTOP_BRFALSE_I4: - BR_UNOP(int32_t, == 0); - break; - case INTOP_BRFALSE_I8: - BR_UNOP(int64_t, == 0); - break; - case INTOP_BRTRUE_I4: - BR_UNOP(int32_t, != 0); - break; - case INTOP_BRTRUE_I8: - BR_UNOP(int64_t, != 0); - break; + case INTOP_BRFALSE_I4: + BR_UNOP(int32_t, == 0); + break; + case INTOP_BRFALSE_I8: + BR_UNOP(int64_t, == 0); + break; + case INTOP_BRTRUE_I4: + BR_UNOP(int32_t, != 0); + break; + case INTOP_BRTRUE_I8: + BR_UNOP(int64_t, != 0); + break; #define BR_BINOP_COND(cond) \ if (cond) \ @@ -316,487 +324,487 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr #define BR_BINOP(datatype, op) \ BR_BINOP_COND(LOCAL_VAR(ip[1], datatype) op LOCAL_VAR(ip[2], datatype)) - case INTOP_BEQ_I4: - BR_BINOP(int32_t, ==); - break; - case INTOP_BEQ_I8: - BR_BINOP(int64_t, ==); - break; - case INTOP_BEQ_R4: - { - float f1 = LOCAL_VAR(ip[1], float); - float f2 = LOCAL_VAR(ip[2], float); - BR_BINOP_COND(!isunordered(f1, f2) && f1 == f2); - break; - } - case INTOP_BEQ_R8: - { - double d1 = LOCAL_VAR(ip[1], double); - double d2 = LOCAL_VAR(ip[2], double); - BR_BINOP_COND(!isunordered(d1, d2) && d1 == d2); - break; - } - case INTOP_BGE_I4: - BR_BINOP(int32_t, >=); - break; - case INTOP_BGE_I8: - BR_BINOP(int64_t, >=); - break; - case INTOP_BGE_R4: - { - float f1 = LOCAL_VAR(ip[1], float); - float f2 = LOCAL_VAR(ip[2], float); - BR_BINOP_COND(!isunordered(f1, f2) && f1 >= f2); - break; - } - case INTOP_BGE_R8: - { - double d1 = LOCAL_VAR(ip[1], double); - double d2 = LOCAL_VAR(ip[2], double); - BR_BINOP_COND(!isunordered(d1, d2) && d1 >= d2); - break; - } - case INTOP_BGT_I4: - BR_BINOP(int32_t, >); - break; - case INTOP_BGT_I8: - BR_BINOP(int64_t, >); - break; - case INTOP_BGT_R4: - { - float f1 = LOCAL_VAR(ip[1], float); - float f2 = LOCAL_VAR(ip[2], float); - BR_BINOP_COND(!isunordered(f1, f2) && f1 > f2); - break; - } - case INTOP_BGT_R8: - { - double d1 = LOCAL_VAR(ip[1], double); - double d2 = LOCAL_VAR(ip[2], double); - BR_BINOP_COND(!isunordered(d1, d2) && d1 > d2); - break; - } - case INTOP_BLT_I4: - BR_BINOP(int32_t, <); - break; - case INTOP_BLT_I8: - BR_BINOP(int64_t, <); - break; - case INTOP_BLT_R4: - { - float f1 = LOCAL_VAR(ip[1], float); - float f2 = LOCAL_VAR(ip[2], float); - BR_BINOP_COND(!isunordered(f1, f2) && f1 < f2); - break; - } - case INTOP_BLT_R8: - { - double d1 = LOCAL_VAR(ip[1], double); - double d2 = LOCAL_VAR(ip[2], double); - BR_BINOP_COND(!isunordered(d1, d2) && d1 < d2); - break; - } - case INTOP_BLE_I4: - BR_BINOP(int32_t, <=); - break; - case INTOP_BLE_I8: - BR_BINOP(int64_t, <=); - break; - case INTOP_BLE_R4: - { - float f1 = LOCAL_VAR(ip[1], float); - float f2 = LOCAL_VAR(ip[2], float); - BR_BINOP_COND(!isunordered(f1, f2) && f1 <= f2); - break; - } - case INTOP_BLE_R8: - { - double d1 = LOCAL_VAR(ip[1], double); - double d2 = LOCAL_VAR(ip[2], double); - BR_BINOP_COND(!isunordered(d1, d2) && d1 <= d2); - break; - } - case INTOP_BNE_UN_I4: - BR_BINOP(uint32_t, !=); - break; - case INTOP_BNE_UN_I8: - BR_BINOP(uint64_t, !=); - break; - case INTOP_BNE_UN_R4: - { - float f1 = LOCAL_VAR(ip[1], float); - float f2 = LOCAL_VAR(ip[2], float); - BR_BINOP_COND(isunordered(f1, f2) || f1 != f2); - break; - } - case INTOP_BNE_UN_R8: - { - double d1 = LOCAL_VAR(ip[1], double); - double d2 = LOCAL_VAR(ip[2], double); - BR_BINOP_COND(isunordered(d1, d2) || d1 != d2); - break; - } - case INTOP_BGE_UN_I4: - BR_BINOP(uint32_t, >=); - break; - case INTOP_BGE_UN_I8: - BR_BINOP(uint64_t, >=); - break; - case INTOP_BGE_UN_R4: - { - float f1 = LOCAL_VAR(ip[1], float); - float f2 = LOCAL_VAR(ip[2], float); - BR_BINOP_COND(isunordered(f1, f2) || f1 >= f2); - break; - } - case INTOP_BGE_UN_R8: - { - double d1 = LOCAL_VAR(ip[1], double); - double d2 = LOCAL_VAR(ip[2], double); - BR_BINOP_COND(isunordered(d1, d2) || d1 >= d2); - break; - } - case INTOP_BGT_UN_I4: - BR_BINOP(uint32_t, >); - break; - case INTOP_BGT_UN_I8: - BR_BINOP(uint64_t, >); - break; - case INTOP_BGT_UN_R4: - { - float f1 = LOCAL_VAR(ip[1], float); - float f2 = LOCAL_VAR(ip[2], float); - BR_BINOP_COND(isunordered(f1, f2) || f1 > f2); - break; - } - case INTOP_BGT_UN_R8: - { - double d1 = LOCAL_VAR(ip[1], double); - double d2 = LOCAL_VAR(ip[2], double); - BR_BINOP_COND(isunordered(d1, d2) || d1 > d2); - break; - } - case INTOP_BLE_UN_I4: - BR_BINOP(uint32_t, <=); - break; - case INTOP_BLE_UN_I8: - BR_BINOP(uint64_t, <=); - break; - case INTOP_BLE_UN_R4: - { - float f1 = LOCAL_VAR(ip[1], float); - float f2 = LOCAL_VAR(ip[2], float); - BR_BINOP_COND(isunordered(f1, f2) || f1 <= f2); - break; - } - case INTOP_BLE_UN_R8: - { - double d1 = LOCAL_VAR(ip[1], double); - double d2 = LOCAL_VAR(ip[2], double); - BR_BINOP_COND(isunordered(d1, d2) || d1 <= d2); - break; - } - case INTOP_BLT_UN_I4: - BR_BINOP(uint32_t, <); - break; - case INTOP_BLT_UN_I8: - BR_BINOP(uint64_t, <); - break; - case INTOP_BLT_UN_R4: - { - float f1 = LOCAL_VAR(ip[1], float); - float f2 = LOCAL_VAR(ip[2], float); - BR_BINOP_COND(isunordered(f1, f2) || f1 < f2); - break; - } - case INTOP_BLT_UN_R8: - { - double d1 = LOCAL_VAR(ip[1], double); - double d2 = LOCAL_VAR(ip[2], double); - BR_BINOP_COND(isunordered(d1, d2) || d1 < d2); - break; - } + case INTOP_BEQ_I4: + BR_BINOP(int32_t, ==); + break; + case INTOP_BEQ_I8: + BR_BINOP(int64_t, ==); + break; + case INTOP_BEQ_R4: + { + float f1 = LOCAL_VAR(ip[1], float); + float f2 = LOCAL_VAR(ip[2], float); + BR_BINOP_COND(!isunordered(f1, f2) && f1 == f2); + break; + } + case INTOP_BEQ_R8: + { + double d1 = LOCAL_VAR(ip[1], double); + double d2 = LOCAL_VAR(ip[2], double); + BR_BINOP_COND(!isunordered(d1, d2) && d1 == d2); + break; + } + case INTOP_BGE_I4: + BR_BINOP(int32_t, >=); + break; + case INTOP_BGE_I8: + BR_BINOP(int64_t, >=); + break; + case INTOP_BGE_R4: + { + float f1 = LOCAL_VAR(ip[1], float); + float f2 = LOCAL_VAR(ip[2], float); + BR_BINOP_COND(!isunordered(f1, f2) && f1 >= f2); + break; + } + case INTOP_BGE_R8: + { + double d1 = LOCAL_VAR(ip[1], double); + double d2 = LOCAL_VAR(ip[2], double); + BR_BINOP_COND(!isunordered(d1, d2) && d1 >= d2); + break; + } + case INTOP_BGT_I4: + BR_BINOP(int32_t, >); + break; + case INTOP_BGT_I8: + BR_BINOP(int64_t, >); + break; + case INTOP_BGT_R4: + { + float f1 = LOCAL_VAR(ip[1], float); + float f2 = LOCAL_VAR(ip[2], float); + BR_BINOP_COND(!isunordered(f1, f2) && f1 > f2); + break; + } + case INTOP_BGT_R8: + { + double d1 = LOCAL_VAR(ip[1], double); + double d2 = LOCAL_VAR(ip[2], double); + BR_BINOP_COND(!isunordered(d1, d2) && d1 > d2); + break; + } + case INTOP_BLT_I4: + BR_BINOP(int32_t, <); + break; + case INTOP_BLT_I8: + BR_BINOP(int64_t, <); + break; + case INTOP_BLT_R4: + { + float f1 = LOCAL_VAR(ip[1], float); + float f2 = LOCAL_VAR(ip[2], float); + BR_BINOP_COND(!isunordered(f1, f2) && f1 < f2); + break; + } + case INTOP_BLT_R8: + { + double d1 = LOCAL_VAR(ip[1], double); + double d2 = LOCAL_VAR(ip[2], double); + BR_BINOP_COND(!isunordered(d1, d2) && d1 < d2); + break; + } + case INTOP_BLE_I4: + BR_BINOP(int32_t, <=); + break; + case INTOP_BLE_I8: + BR_BINOP(int64_t, <=); + break; + case INTOP_BLE_R4: + { + float f1 = LOCAL_VAR(ip[1], float); + float f2 = LOCAL_VAR(ip[2], float); + BR_BINOP_COND(!isunordered(f1, f2) && f1 <= f2); + break; + } + case INTOP_BLE_R8: + { + double d1 = LOCAL_VAR(ip[1], double); + double d2 = LOCAL_VAR(ip[2], double); + BR_BINOP_COND(!isunordered(d1, d2) && d1 <= d2); + break; + } + case INTOP_BNE_UN_I4: + BR_BINOP(uint32_t, !=); + break; + case INTOP_BNE_UN_I8: + BR_BINOP(uint64_t, !=); + break; + case INTOP_BNE_UN_R4: + { + float f1 = LOCAL_VAR(ip[1], float); + float f2 = LOCAL_VAR(ip[2], float); + BR_BINOP_COND(isunordered(f1, f2) || f1 != f2); + break; + } + case INTOP_BNE_UN_R8: + { + double d1 = LOCAL_VAR(ip[1], double); + double d2 = LOCAL_VAR(ip[2], double); + BR_BINOP_COND(isunordered(d1, d2) || d1 != d2); + break; + } + case INTOP_BGE_UN_I4: + BR_BINOP(uint32_t, >=); + break; + case INTOP_BGE_UN_I8: + BR_BINOP(uint64_t, >=); + break; + case INTOP_BGE_UN_R4: + { + float f1 = LOCAL_VAR(ip[1], float); + float f2 = LOCAL_VAR(ip[2], float); + BR_BINOP_COND(isunordered(f1, f2) || f1 >= f2); + break; + } + case INTOP_BGE_UN_R8: + { + double d1 = LOCAL_VAR(ip[1], double); + double d2 = LOCAL_VAR(ip[2], double); + BR_BINOP_COND(isunordered(d1, d2) || d1 >= d2); + break; + } + case INTOP_BGT_UN_I4: + BR_BINOP(uint32_t, >); + break; + case INTOP_BGT_UN_I8: + BR_BINOP(uint64_t, >); + break; + case INTOP_BGT_UN_R4: + { + float f1 = LOCAL_VAR(ip[1], float); + float f2 = LOCAL_VAR(ip[2], float); + BR_BINOP_COND(isunordered(f1, f2) || f1 > f2); + break; + } + case INTOP_BGT_UN_R8: + { + double d1 = LOCAL_VAR(ip[1], double); + double d2 = LOCAL_VAR(ip[2], double); + BR_BINOP_COND(isunordered(d1, d2) || d1 > d2); + break; + } + case INTOP_BLE_UN_I4: + BR_BINOP(uint32_t, <=); + break; + case INTOP_BLE_UN_I8: + BR_BINOP(uint64_t, <=); + break; + case INTOP_BLE_UN_R4: + { + float f1 = LOCAL_VAR(ip[1], float); + float f2 = LOCAL_VAR(ip[2], float); + BR_BINOP_COND(isunordered(f1, f2) || f1 <= f2); + break; + } + case INTOP_BLE_UN_R8: + { + double d1 = LOCAL_VAR(ip[1], double); + double d2 = LOCAL_VAR(ip[2], double); + BR_BINOP_COND(isunordered(d1, d2) || d1 <= d2); + break; + } + case INTOP_BLT_UN_I4: + BR_BINOP(uint32_t, <); + break; + case INTOP_BLT_UN_I8: + BR_BINOP(uint64_t, <); + break; + case INTOP_BLT_UN_R4: + { + float f1 = LOCAL_VAR(ip[1], float); + float f2 = LOCAL_VAR(ip[2], float); + BR_BINOP_COND(isunordered(f1, f2) || f1 < f2); + break; + } + case INTOP_BLT_UN_R8: + { + double d1 = LOCAL_VAR(ip[1], double); + double d2 = LOCAL_VAR(ip[2], double); + BR_BINOP_COND(isunordered(d1, d2) || d1 < d2); + break; + } - case INTOP_ADD_I4: - LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) + LOCAL_VAR(ip[3], int32_t); - ip += 4; - break; - case INTOP_ADD_I8: - LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int64_t) + LOCAL_VAR(ip[3], int64_t); - ip += 4; - break; - case INTOP_ADD_R4: - LOCAL_VAR(ip[1], float) = LOCAL_VAR(ip[2], float) + LOCAL_VAR(ip[3], float); - ip += 4; - break; - case INTOP_ADD_R8: - LOCAL_VAR(ip[1], double) = LOCAL_VAR(ip[2], double) + LOCAL_VAR(ip[3], double); - ip += 4; - break; - case INTOP_ADD_I4_IMM: - LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) + ip[3]; - ip += 4; - break; - case INTOP_ADD_I8_IMM: - LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int64_t) + ip[3]; - ip += 4; - break; - case INTOP_SUB_I4: - LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) - LOCAL_VAR(ip[3], int32_t); - ip += 4; - break; - case INTOP_SUB_I8: - LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int64_t) - LOCAL_VAR(ip[3], int64_t); - ip += 4; - break; - case INTOP_SUB_R4: - LOCAL_VAR(ip[1], float) = LOCAL_VAR(ip[2], float) - LOCAL_VAR(ip[3], float); - ip += 4; - break; - case INTOP_SUB_R8: - LOCAL_VAR(ip[1], double) = LOCAL_VAR(ip[2], double) - LOCAL_VAR(ip[3], double); - ip += 4; - break; - - case INTOP_MUL_I4: - LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) * LOCAL_VAR(ip[3], int32_t); - ip += 4; - break; - case INTOP_MUL_I8: - LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int64_t) * LOCAL_VAR(ip[3], int64_t); - ip += 4; - break; - case INTOP_MUL_R4: - LOCAL_VAR(ip[1], float) = LOCAL_VAR(ip[2], float) * LOCAL_VAR(ip[3], float); - ip += 4; - break; - case INTOP_MUL_R8: - LOCAL_VAR(ip[1], double) = LOCAL_VAR(ip[2], double) * LOCAL_VAR(ip[3], double); - ip += 4; - break; - case INTOP_MUL_OVF_I4: - { - int32_t i1 = LOCAL_VAR(ip[2], int32_t); - int32_t i2 = LOCAL_VAR(ip[3], int32_t); - int32_t i3; - if (!ClrSafeInt::multiply(i1, i2, i3)) - assert(0); // Interpreter-TODO: OverflowException - LOCAL_VAR(ip[1], int32_t) = i3; - ip += 4; - break; - } + case INTOP_ADD_I4: + LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) + LOCAL_VAR(ip[3], int32_t); + ip += 4; + break; + case INTOP_ADD_I8: + LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int64_t) + LOCAL_VAR(ip[3], int64_t); + ip += 4; + break; + case INTOP_ADD_R4: + LOCAL_VAR(ip[1], float) = LOCAL_VAR(ip[2], float) + LOCAL_VAR(ip[3], float); + ip += 4; + break; + case INTOP_ADD_R8: + LOCAL_VAR(ip[1], double) = LOCAL_VAR(ip[2], double) + LOCAL_VAR(ip[3], double); + ip += 4; + break; + case INTOP_ADD_I4_IMM: + LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) + ip[3]; + ip += 4; + break; + case INTOP_ADD_I8_IMM: + LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int64_t) + ip[3]; + ip += 4; + break; + case INTOP_SUB_I4: + LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) - LOCAL_VAR(ip[3], int32_t); + ip += 4; + break; + case INTOP_SUB_I8: + LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int64_t) - LOCAL_VAR(ip[3], int64_t); + ip += 4; + break; + case INTOP_SUB_R4: + LOCAL_VAR(ip[1], float) = LOCAL_VAR(ip[2], float) - LOCAL_VAR(ip[3], float); + ip += 4; + break; + case INTOP_SUB_R8: + LOCAL_VAR(ip[1], double) = LOCAL_VAR(ip[2], double) - LOCAL_VAR(ip[3], double); + ip += 4; + break; + + case INTOP_MUL_I4: + LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) * LOCAL_VAR(ip[3], int32_t); + ip += 4; + break; + case INTOP_MUL_I8: + LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int64_t) * LOCAL_VAR(ip[3], int64_t); + ip += 4; + break; + case INTOP_MUL_R4: + LOCAL_VAR(ip[1], float) = LOCAL_VAR(ip[2], float) * LOCAL_VAR(ip[3], float); + ip += 4; + break; + case INTOP_MUL_R8: + LOCAL_VAR(ip[1], double) = LOCAL_VAR(ip[2], double) * LOCAL_VAR(ip[3], double); + ip += 4; + break; + case INTOP_MUL_OVF_I4: + { + int32_t i1 = LOCAL_VAR(ip[2], int32_t); + int32_t i2 = LOCAL_VAR(ip[3], int32_t); + int32_t i3; + if (!ClrSafeInt::multiply(i1, i2, i3)) + assert(0); // Interpreter-TODO: OverflowException + LOCAL_VAR(ip[1], int32_t) = i3; + ip += 4; + break; + } - case INTOP_MUL_OVF_I8: - { - int64_t i1 = LOCAL_VAR(ip[2], int64_t); - int64_t i2 = LOCAL_VAR(ip[3], int64_t); - int64_t i3; - if (!ClrSafeInt::multiply(i1, i2, i3)) - assert(0); // Interpreter-TODO: OverflowException - LOCAL_VAR(ip[1], int64_t) = i3; - ip += 4; - break; - } + case INTOP_MUL_OVF_I8: + { + int64_t i1 = LOCAL_VAR(ip[2], int64_t); + int64_t i2 = LOCAL_VAR(ip[3], int64_t); + int64_t i3; + if (!ClrSafeInt::multiply(i1, i2, i3)) + assert(0); // Interpreter-TODO: OverflowException + LOCAL_VAR(ip[1], int64_t) = i3; + ip += 4; + break; + } - case INTOP_MUL_OVF_UN_I4: - { - uint32_t i1 = LOCAL_VAR(ip[2], uint32_t); - uint32_t i2 = LOCAL_VAR(ip[3], uint32_t); - uint32_t i3; - if (!ClrSafeInt::multiply(i1, i2, i3)) - assert(0); // Interpreter-TODO: OverflowException - LOCAL_VAR(ip[1], uint32_t) = i3; - ip += 4; - break; - } + case INTOP_MUL_OVF_UN_I4: + { + uint32_t i1 = LOCAL_VAR(ip[2], uint32_t); + uint32_t i2 = LOCAL_VAR(ip[3], uint32_t); + uint32_t i3; + if (!ClrSafeInt::multiply(i1, i2, i3)) + assert(0); // Interpreter-TODO: OverflowException + LOCAL_VAR(ip[1], uint32_t) = i3; + ip += 4; + break; + } - case INTOP_MUL_OVF_UN_I8: - { - uint64_t i1 = LOCAL_VAR(ip[2], uint64_t); - uint64_t i2 = LOCAL_VAR(ip[3], uint64_t); - uint64_t i3; - if (!ClrSafeInt::multiply(i1, i2, i3)) - assert(0); // Interpreter-TODO: OverflowException - LOCAL_VAR(ip[1], uint64_t) = i3; - ip += 4; - break; - } - case INTOP_DIV_I4: - { - int32_t i1 = LOCAL_VAR(ip[2], int32_t); - int32_t i2 = LOCAL_VAR(ip[3], int32_t); - if (i2 == 0) - assert(0); // Interpreter-TODO: DivideByZeroException - if (i2 == -1 && i1 == INT32_MIN) - assert(0); // Interpreter-TODO: OverflowException - LOCAL_VAR(ip[1], int32_t) = i1 / i2; - ip += 4; - break; - } - case INTOP_DIV_I8: - { - int64_t l1 = LOCAL_VAR(ip[2], int64_t); - int64_t l2 = LOCAL_VAR(ip[3], int64_t); - if (l2 == 0) - assert(0); // Interpreter-TODO: DivideByZeroException - if (l2 == -1 && l1 == INT64_MIN) - assert(0); // Interpreter-TODO: OverflowException - LOCAL_VAR(ip[1], int64_t) = l1 / l2; - ip += 4; - break; - } - case INTOP_DIV_R4: - LOCAL_VAR(ip[1], float) = LOCAL_VAR(ip[2], float) / LOCAL_VAR(ip[3], float); - ip += 4; - break; - case INTOP_DIV_R8: - LOCAL_VAR(ip[1], double) = LOCAL_VAR(ip[2], double) / LOCAL_VAR(ip[3], double); - ip += 4; - break; - case INTOP_DIV_UN_I4: - { - uint32_t i2 = LOCAL_VAR(ip[3], uint32_t); - if (i2 == 0) - assert(0); // Interpreter-TODO: DivideByZeroException - LOCAL_VAR(ip[1], uint32_t) = LOCAL_VAR(ip[2], uint32_t) / i2; - ip += 4; - break; - } - case INTOP_DIV_UN_I8: - { - uint64_t l2 = LOCAL_VAR(ip[3], uint64_t); - if (l2 == 0) - assert(0); // Interpreter-TODO: DivideByZeroException - LOCAL_VAR(ip[1], uint64_t) = LOCAL_VAR(ip[2], uint64_t) / l2; - ip += 4; - break; - } + case INTOP_MUL_OVF_UN_I8: + { + uint64_t i1 = LOCAL_VAR(ip[2], uint64_t); + uint64_t i2 = LOCAL_VAR(ip[3], uint64_t); + uint64_t i3; + if (!ClrSafeInt::multiply(i1, i2, i3)) + assert(0); // Interpreter-TODO: OverflowException + LOCAL_VAR(ip[1], uint64_t) = i3; + ip += 4; + break; + } + case INTOP_DIV_I4: + { + int32_t i1 = LOCAL_VAR(ip[2], int32_t); + int32_t i2 = LOCAL_VAR(ip[3], int32_t); + if (i2 == 0) + assert(0); // Interpreter-TODO: DivideByZeroException + if (i2 == -1 && i1 == INT32_MIN) + assert(0); // Interpreter-TODO: OverflowException + LOCAL_VAR(ip[1], int32_t) = i1 / i2; + ip += 4; + break; + } + case INTOP_DIV_I8: + { + int64_t l1 = LOCAL_VAR(ip[2], int64_t); + int64_t l2 = LOCAL_VAR(ip[3], int64_t); + if (l2 == 0) + assert(0); // Interpreter-TODO: DivideByZeroException + if (l2 == -1 && l1 == INT64_MIN) + assert(0); // Interpreter-TODO: OverflowException + LOCAL_VAR(ip[1], int64_t) = l1 / l2; + ip += 4; + break; + } + case INTOP_DIV_R4: + LOCAL_VAR(ip[1], float) = LOCAL_VAR(ip[2], float) / LOCAL_VAR(ip[3], float); + ip += 4; + break; + case INTOP_DIV_R8: + LOCAL_VAR(ip[1], double) = LOCAL_VAR(ip[2], double) / LOCAL_VAR(ip[3], double); + ip += 4; + break; + case INTOP_DIV_UN_I4: + { + uint32_t i2 = LOCAL_VAR(ip[3], uint32_t); + if (i2 == 0) + assert(0); // Interpreter-TODO: DivideByZeroException + LOCAL_VAR(ip[1], uint32_t) = LOCAL_VAR(ip[2], uint32_t) / i2; + ip += 4; + break; + } + case INTOP_DIV_UN_I8: + { + uint64_t l2 = LOCAL_VAR(ip[3], uint64_t); + if (l2 == 0) + assert(0); // Interpreter-TODO: DivideByZeroException + LOCAL_VAR(ip[1], uint64_t) = LOCAL_VAR(ip[2], uint64_t) / l2; + ip += 4; + break; + } - case INTOP_REM_I4: - { - int32_t i1 = LOCAL_VAR(ip[2], int32_t); - int32_t i2 = LOCAL_VAR(ip[3], int32_t); - if (i2 == 0) - assert(0); // Interpreter-TODO: DivideByZeroException - if (i2 == -1 && i1 == INT32_MIN) - assert(0); // Interpreter-TODO: OverflowException - LOCAL_VAR(ip[1], int32_t) = i1 % i2; - ip += 4; - break; - } - case INTOP_REM_I8: - { - int64_t l1 = LOCAL_VAR(ip[2], int64_t); - int64_t l2 = LOCAL_VAR(ip[3], int64_t); - if (l2 == 0) - assert(0); // Interpreter-TODO: DivideByZeroException - if (l2 == -1 && l1 == INT64_MIN) - assert(0); // Interpreter-TODO: OverflowException - LOCAL_VAR(ip[1], int64_t) = l1 % l2; - ip += 4; - break; - } - case INTOP_REM_R4: - LOCAL_VAR(ip[1], float) = fmodf(LOCAL_VAR(ip[2], float), LOCAL_VAR(ip[3], float)); - ip += 4; - break; - case INTOP_REM_R8: - LOCAL_VAR(ip[1], double) = fmod(LOCAL_VAR(ip[2], double), LOCAL_VAR(ip[3], double)); - ip += 4; - break; - case INTOP_REM_UN_I4: - { - uint32_t i2 = LOCAL_VAR(ip[3], uint32_t); - if (i2 == 0) - assert(0); // Interpreter-TODO: DivideByZeroException - LOCAL_VAR(ip[1], uint32_t) = LOCAL_VAR(ip[2], uint32_t) % i2; - ip += 4; - break; - } - case INTOP_REM_UN_I8: - { - uint64_t l2 = LOCAL_VAR(ip[3], uint64_t); - if (l2 == 0) - assert(0); // Interpreter-TODO: DivideByZeroException - LOCAL_VAR(ip[1], uint64_t) = LOCAL_VAR(ip[2], uint64_t) % l2; - ip += 4; - break; - } + case INTOP_REM_I4: + { + int32_t i1 = LOCAL_VAR(ip[2], int32_t); + int32_t i2 = LOCAL_VAR(ip[3], int32_t); + if (i2 == 0) + assert(0); // Interpreter-TODO: DivideByZeroException + if (i2 == -1 && i1 == INT32_MIN) + assert(0); // Interpreter-TODO: OverflowException + LOCAL_VAR(ip[1], int32_t) = i1 % i2; + ip += 4; + break; + } + case INTOP_REM_I8: + { + int64_t l1 = LOCAL_VAR(ip[2], int64_t); + int64_t l2 = LOCAL_VAR(ip[3], int64_t); + if (l2 == 0) + assert(0); // Interpreter-TODO: DivideByZeroException + if (l2 == -1 && l1 == INT64_MIN) + assert(0); // Interpreter-TODO: OverflowException + LOCAL_VAR(ip[1], int64_t) = l1 % l2; + ip += 4; + break; + } + case INTOP_REM_R4: + LOCAL_VAR(ip[1], float) = fmodf(LOCAL_VAR(ip[2], float), LOCAL_VAR(ip[3], float)); + ip += 4; + break; + case INTOP_REM_R8: + LOCAL_VAR(ip[1], double) = fmod(LOCAL_VAR(ip[2], double), LOCAL_VAR(ip[3], double)); + ip += 4; + break; + case INTOP_REM_UN_I4: + { + uint32_t i2 = LOCAL_VAR(ip[3], uint32_t); + if (i2 == 0) + assert(0); // Interpreter-TODO: DivideByZeroException + LOCAL_VAR(ip[1], uint32_t) = LOCAL_VAR(ip[2], uint32_t) % i2; + ip += 4; + break; + } + case INTOP_REM_UN_I8: + { + uint64_t l2 = LOCAL_VAR(ip[3], uint64_t); + if (l2 == 0) + assert(0); // Interpreter-TODO: DivideByZeroException + LOCAL_VAR(ip[1], uint64_t) = LOCAL_VAR(ip[2], uint64_t) % l2; + ip += 4; + break; + } - case INTOP_SHL_I4: - LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) << LOCAL_VAR(ip[3], int32_t); - ip += 4; - break; - case INTOP_SHL_I8: - LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int64_t) << LOCAL_VAR(ip[3], int32_t); - ip += 4; - break; - case INTOP_SHR_I4: - LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) >> LOCAL_VAR(ip[3], int32_t); - ip += 4; - break; - case INTOP_SHR_I8: - LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int64_t) >> LOCAL_VAR(ip[3], int32_t); - ip += 4; - break; - case INTOP_SHR_UN_I4: - LOCAL_VAR(ip[1], uint32_t) = LOCAL_VAR(ip[2], uint32_t) >> LOCAL_VAR(ip[3], int32_t); - ip += 4; - break; - case INTOP_SHR_UN_I8: - LOCAL_VAR(ip[1], uint64_t) = LOCAL_VAR(ip[2], uint64_t) >> LOCAL_VAR(ip[3], int32_t); - ip += 4; - break; - - case INTOP_NEG_I4: - LOCAL_VAR(ip[1], int32_t) = - LOCAL_VAR(ip[2], int32_t); - ip += 3; - break; - case INTOP_NEG_I8: - LOCAL_VAR(ip[1], int64_t) = - LOCAL_VAR(ip[2], int64_t); - ip += 3; - break; - case INTOP_NEG_R4: - LOCAL_VAR(ip[1], float) = - LOCAL_VAR(ip[2], float); - ip += 3; - break; - case INTOP_NEG_R8: - LOCAL_VAR(ip[1], double) = - LOCAL_VAR(ip[2], double); - ip += 3; - break; - case INTOP_NOT_I4: - LOCAL_VAR(ip[1], int32_t) = ~ LOCAL_VAR(ip[2], int32_t); - ip += 3; - break; - case INTOP_NOT_I8: - LOCAL_VAR(ip[1], int64_t) = ~ LOCAL_VAR(ip[2], int64_t); - ip += 3; - break; - - case INTOP_AND_I4: - LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) & LOCAL_VAR(ip[3], int32_t); - ip += 4; - break; - case INTOP_AND_I8: - LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int64_t) & LOCAL_VAR(ip[3], int64_t); - ip += 4; - break; - case INTOP_OR_I4: - LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) | LOCAL_VAR(ip[3], int32_t); - ip += 4; - break; - case INTOP_OR_I8: - LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int64_t) | LOCAL_VAR(ip[3], int64_t); - ip += 4; - break; - case INTOP_XOR_I4: - LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) ^ LOCAL_VAR(ip[3], int32_t); - ip += 4; - break; - case INTOP_XOR_I8: - LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int64_t) ^ LOCAL_VAR(ip[3], int64_t); - ip += 4; - break; + case INTOP_SHL_I4: + LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) << LOCAL_VAR(ip[3], int32_t); + ip += 4; + break; + case INTOP_SHL_I8: + LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int64_t) << LOCAL_VAR(ip[3], int32_t); + ip += 4; + break; + case INTOP_SHR_I4: + LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) >> LOCAL_VAR(ip[3], int32_t); + ip += 4; + break; + case INTOP_SHR_I8: + LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int64_t) >> LOCAL_VAR(ip[3], int32_t); + ip += 4; + break; + case INTOP_SHR_UN_I4: + LOCAL_VAR(ip[1], uint32_t) = LOCAL_VAR(ip[2], uint32_t) >> LOCAL_VAR(ip[3], int32_t); + ip += 4; + break; + case INTOP_SHR_UN_I8: + LOCAL_VAR(ip[1], uint64_t) = LOCAL_VAR(ip[2], uint64_t) >> LOCAL_VAR(ip[3], int32_t); + ip += 4; + break; + + case INTOP_NEG_I4: + LOCAL_VAR(ip[1], int32_t) = - LOCAL_VAR(ip[2], int32_t); + ip += 3; + break; + case INTOP_NEG_I8: + LOCAL_VAR(ip[1], int64_t) = - LOCAL_VAR(ip[2], int64_t); + ip += 3; + break; + case INTOP_NEG_R4: + LOCAL_VAR(ip[1], float) = - LOCAL_VAR(ip[2], float); + ip += 3; + break; + case INTOP_NEG_R8: + LOCAL_VAR(ip[1], double) = - LOCAL_VAR(ip[2], double); + ip += 3; + break; + case INTOP_NOT_I4: + LOCAL_VAR(ip[1], int32_t) = ~ LOCAL_VAR(ip[2], int32_t); + ip += 3; + break; + case INTOP_NOT_I8: + LOCAL_VAR(ip[1], int64_t) = ~ LOCAL_VAR(ip[2], int64_t); + ip += 3; + break; + + case INTOP_AND_I4: + LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) & LOCAL_VAR(ip[3], int32_t); + ip += 4; + break; + case INTOP_AND_I8: + LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int64_t) & LOCAL_VAR(ip[3], int64_t); + ip += 4; + break; + case INTOP_OR_I4: + LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) | LOCAL_VAR(ip[3], int32_t); + ip += 4; + break; + case INTOP_OR_I8: + LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int64_t) | LOCAL_VAR(ip[3], int64_t); + ip += 4; + break; + case INTOP_XOR_I4: + LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) ^ LOCAL_VAR(ip[3], int32_t); + ip += 4; + break; + case INTOP_XOR_I8: + LOCAL_VAR(ip[1], int64_t) = LOCAL_VAR(ip[2], int64_t) ^ LOCAL_VAR(ip[3], int64_t); + ip += 4; + break; #define CMP_BINOP_FP(datatype, op, noOrderVal) \ do { \ @@ -809,80 +817,80 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr ip += 4; \ } while (0) - case INTOP_CEQ_I4: - LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) == LOCAL_VAR(ip[3], int32_t); - ip += 4; - break; - case INTOP_CEQ_I8: - LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int64_t) == LOCAL_VAR(ip[3], int64_t); - ip += 4; - break; - case INTOP_CEQ_R4: - CMP_BINOP_FP(float, ==, 0); - break; - case INTOP_CEQ_R8: - CMP_BINOP_FP(double, ==, 0); - break; - - case INTOP_CGT_I4: - LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) > LOCAL_VAR(ip[3], int32_t); - ip += 4; - break; - case INTOP_CGT_I8: - LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int64_t) > LOCAL_VAR(ip[3], int64_t); - ip += 4; - break; - case INTOP_CGT_R4: - CMP_BINOP_FP(float, >, 0); - break; - case INTOP_CGT_R8: - CMP_BINOP_FP(double, >, 0); - break; - - case INTOP_CGT_UN_I4: - LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], uint32_t) > LOCAL_VAR(ip[3], uint32_t); - ip += 4; - break; - case INTOP_CGT_UN_I8: - LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], uint32_t) > LOCAL_VAR(ip[3], uint32_t); - ip += 4; - break; - case INTOP_CGT_UN_R4: - CMP_BINOP_FP(float, >, 1); - break; - case INTOP_CGT_UN_R8: - CMP_BINOP_FP(double, >, 1); - break; - - case INTOP_CLT_I4: - LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) < LOCAL_VAR(ip[3], int32_t); - ip += 4; - break; - case INTOP_CLT_I8: - LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int64_t) < LOCAL_VAR(ip[3], int64_t); - ip += 4; - break; - case INTOP_CLT_R4: - CMP_BINOP_FP(float, <, 0); - break; - case INTOP_CLT_R8: - CMP_BINOP_FP(double, <, 0); - break; - - case INTOP_CLT_UN_I4: - LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], uint32_t) < LOCAL_VAR(ip[3], uint32_t); - ip += 4; - break; - case INTOP_CLT_UN_I8: - LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], uint64_t) < LOCAL_VAR(ip[3], uint64_t); - ip += 4; - break; - case INTOP_CLT_UN_R4: - CMP_BINOP_FP(float, <, 1); - break; - case INTOP_CLT_UN_R8: - CMP_BINOP_FP(double, <, 1); - break; + case INTOP_CEQ_I4: + LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) == LOCAL_VAR(ip[3], int32_t); + ip += 4; + break; + case INTOP_CEQ_I8: + LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int64_t) == LOCAL_VAR(ip[3], int64_t); + ip += 4; + break; + case INTOP_CEQ_R4: + CMP_BINOP_FP(float, ==, 0); + break; + case INTOP_CEQ_R8: + CMP_BINOP_FP(double, ==, 0); + break; + + case INTOP_CGT_I4: + LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) > LOCAL_VAR(ip[3], int32_t); + ip += 4; + break; + case INTOP_CGT_I8: + LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int64_t) > LOCAL_VAR(ip[3], int64_t); + ip += 4; + break; + case INTOP_CGT_R4: + CMP_BINOP_FP(float, >, 0); + break; + case INTOP_CGT_R8: + CMP_BINOP_FP(double, >, 0); + break; + + case INTOP_CGT_UN_I4: + LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], uint32_t) > LOCAL_VAR(ip[3], uint32_t); + ip += 4; + break; + case INTOP_CGT_UN_I8: + LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], uint32_t) > LOCAL_VAR(ip[3], uint32_t); + ip += 4; + break; + case INTOP_CGT_UN_R4: + CMP_BINOP_FP(float, >, 1); + break; + case INTOP_CGT_UN_R8: + CMP_BINOP_FP(double, >, 1); + break; + + case INTOP_CLT_I4: + LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int32_t) < LOCAL_VAR(ip[3], int32_t); + ip += 4; + break; + case INTOP_CLT_I8: + LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], int64_t) < LOCAL_VAR(ip[3], int64_t); + ip += 4; + break; + case INTOP_CLT_R4: + CMP_BINOP_FP(float, <, 0); + break; + case INTOP_CLT_R8: + CMP_BINOP_FP(double, <, 0); + break; + + case INTOP_CLT_UN_I4: + LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], uint32_t) < LOCAL_VAR(ip[3], uint32_t); + ip += 4; + break; + case INTOP_CLT_UN_I8: + LOCAL_VAR(ip[1], int32_t) = LOCAL_VAR(ip[2], uint64_t) < LOCAL_VAR(ip[3], uint64_t); + ip += 4; + break; + case INTOP_CLT_UN_R4: + CMP_BINOP_FP(float, <, 1); + break; + case INTOP_CLT_UN_R8: + CMP_BINOP_FP(double, <, 1); + break; #define LDIND(dtype, ftype) \ do { \ @@ -892,38 +900,38 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr ip += 4; \ } while (0) - case INTOP_LDIND_I1: - LDIND(int32_t, int8_t); - break; - case INTOP_LDIND_U1: - LDIND(int32_t, uint8_t); - break; - case INTOP_LDIND_I2: - LDIND(int32_t, int16_t); - break; - case INTOP_LDIND_U2: - LDIND(int32_t, uint16_t); - break; - case INTOP_LDIND_I4: - LDIND(int32_t, int32_t); - break; - case INTOP_LDIND_I8: - LDIND(int64_t, int64_t); - break; - case INTOP_LDIND_R4: - LDIND(float, float); - break; - case INTOP_LDIND_R8: - LDIND(double, double); - break; - case INTOP_LDIND_VT: - { - char *src = LOCAL_VAR(ip[2], char*); - NULL_CHECK(obj); - memcpy(stack + ip[1], (char*)src + ip[3], ip[4]); - ip += 5; - break; - } + case INTOP_LDIND_I1: + LDIND(int32_t, int8_t); + break; + case INTOP_LDIND_U1: + LDIND(int32_t, uint8_t); + break; + case INTOP_LDIND_I2: + LDIND(int32_t, int16_t); + break; + case INTOP_LDIND_U2: + LDIND(int32_t, uint16_t); + break; + case INTOP_LDIND_I4: + LDIND(int32_t, int32_t); + break; + case INTOP_LDIND_I8: + LDIND(int64_t, int64_t); + break; + case INTOP_LDIND_R4: + LDIND(float, float); + break; + case INTOP_LDIND_R8: + LDIND(double, double); + break; + case INTOP_LDIND_VT: + { + char *src = LOCAL_VAR(ip[2], char*); + NULL_CHECK(obj); + memcpy(stack + ip[1], (char*)src + ip[3], ip[4]); + ip += 5; + break; + } #define STIND(dtype, ftype) \ do \ @@ -934,254 +942,299 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr ip += 4; \ } while (0) - case INTOP_STIND_I1: - STIND(int32_t, int8_t); - break; - case INTOP_STIND_U1: - STIND(int32_t, uint8_t); - break; - case INTOP_STIND_I2: - STIND(int32_t, int16_t); - break; - case INTOP_STIND_U2: - STIND(int32_t, uint16_t); - break; - case INTOP_STIND_I4: - STIND(int32_t, int32_t); - break; - case INTOP_STIND_I8: - STIND(int64_t, int64_t); - break; - case INTOP_STIND_R4: - STIND(float, float); - break; - case INTOP_STIND_R8: - STIND(double, double); - break; - case INTOP_STIND_O: - { - char *dst = LOCAL_VAR(ip[1], char*); - OBJECTREF storeObj = LOCAL_VAR(ip[2], OBJECTREF); - NULL_CHECK(obj); - SetObjectReferenceUnchecked((OBJECTREF*)(dst + ip[3]), storeObj); - ip += 4; - break; - } - case INTOP_STIND_VT_NOREF: - { - char *dest = LOCAL_VAR(ip[1], char*); - NULL_CHECK(dest); - memcpyNoGCRefs(dest + ip[3], stack + ip[2], ip[4]); - ip += 5; - break; - } - case INTOP_STIND_VT: - { - MethodTable *pMT = (MethodTable*)pMethod->pDataItems[ip[4]]; - char *dest = LOCAL_VAR(ip[1], char*); - NULL_CHECK(dest); - CopyValueClassUnchecked(dest + ip[3], stack + ip[2], pMT); - ip += 5; - break; - } - case INTOP_LDFLDA: - { - char *src = LOCAL_VAR(ip[2], char*); - NULL_CHECK(src); - LOCAL_VAR(ip[1], char*) = src + ip[3]; - ip += 4; - break; - } - - case INTOP_CALL_HELPER_PP: - { - HELPER_FTN_PP helperFtn = (HELPER_FTN_PP)pMethod->pDataItems[ip[2]]; - HELPER_FTN_PP* helperFtnSlot = (HELPER_FTN_PP*)pMethod->pDataItems[ip[3]]; - void* helperArg = pMethod->pDataItems[ip[4]]; - - if (!helperFtn) - helperFtn = *helperFtnSlot; - // This can call either native or compiled managed code. For an interpreter - // only configuration, this might be problematic, at least performance wise. - // FIXME We will need to handle exception throwing here. - LOCAL_VAR(ip[1], void*) = helperFtn(helperArg); - - ip += 5; - break; - } - case INTOP_CALLVIRT: - { - returnOffset = ip[1]; - callArgsOffset = ip[2]; - methodSlot = ip[3]; - - MethodDesc *pMD = (MethodDesc*)pMethod->pDataItems[methodSlot]; - - OBJECTREF *pThisArg = LOCAL_VAR_ADDR(callArgsOffset, OBJECTREF); - NULL_CHECK(*pThisArg); - - // Interpreter-TODO - // This needs to be optimized, not operating at MethodDesc level, rather with ftnptr - // slots containing the interpreter IR pointer - pMD = pMD->GetMethodDescOfVirtualizedCode(pThisArg, pMD->GetMethodTable()); - - PCODE code = pMD->GetNativeCode(); - if (!code) + case INTOP_STIND_I1: + STIND(int32_t, int8_t); + break; + case INTOP_STIND_U1: + STIND(int32_t, uint8_t); + break; + case INTOP_STIND_I2: + STIND(int32_t, int16_t); + break; + case INTOP_STIND_U2: + STIND(int32_t, uint16_t); + break; + case INTOP_STIND_I4: + STIND(int32_t, int32_t); + break; + case INTOP_STIND_I8: + STIND(int64_t, int64_t); + break; + case INTOP_STIND_R4: + STIND(float, float); + break; + case INTOP_STIND_R8: + STIND(double, double); + break; + case INTOP_STIND_O: { - pInterpreterFrame->SetTopInterpMethodContextFrame(pFrame); - GCX_PREEMP(); - pMD->PrepareInitialCode(CallerGCMode::Coop); - code = pMD->GetNativeCode(); + char *dst = LOCAL_VAR(ip[1], char*); + OBJECTREF storeObj = LOCAL_VAR(ip[2], OBJECTREF); + NULL_CHECK(obj); + SetObjectReferenceUnchecked((OBJECTREF*)(dst + ip[3]), storeObj); + ip += 4; + break; + } + case INTOP_STIND_VT_NOREF: + { + char *dest = LOCAL_VAR(ip[1], char*); + NULL_CHECK(dest); + memcpyNoGCRefs(dest + ip[3], stack + ip[2], ip[4]); + ip += 5; + break; + } + case INTOP_STIND_VT: + { + MethodTable *pMT = (MethodTable*)pMethod->pDataItems[ip[4]]; + char *dest = LOCAL_VAR(ip[1], char*); + NULL_CHECK(dest); + CopyValueClassUnchecked(dest + ip[3], stack + ip[2], pMT); + ip += 5; + break; + } + case INTOP_LDFLDA: + { + char *src = LOCAL_VAR(ip[2], char*); + NULL_CHECK(src); + LOCAL_VAR(ip[1], char*) = src + ip[3]; + ip += 4; + break; } - targetIp = (const int32_t*)code; - ip += 4; - // Interpreter-TODO unbox if target method class is valuetype - goto CALL_TARGET_IP; - } - - case INTOP_CALL: - { - returnOffset = ip[1]; - callArgsOffset = ip[2]; - methodSlot = ip[3]; - ip += 4; -CALL_INTERP_SLOT: + case INTOP_CALL_HELPER_PP: { - size_t targetMethod = (size_t)pMethod->pDataItems[methodSlot]; - if (targetMethod & INTERP_METHOD_DESC_TAG) + HELPER_FTN_PP helperFtn = (HELPER_FTN_PP)pMethod->pDataItems[ip[2]]; + HELPER_FTN_PP* helperFtnSlot = (HELPER_FTN_PP*)pMethod->pDataItems[ip[3]]; + void* helperArg = pMethod->pDataItems[ip[4]]; + + if (!helperFtn) + helperFtn = *helperFtnSlot; + // This can call either native or compiled managed code. For an interpreter + // only configuration, this might be problematic, at least performance wise. + // FIXME We will need to handle exception throwing here. + LOCAL_VAR(ip[1], void*) = helperFtn(helperArg); + + ip += 5; + break; + } + case INTOP_CALLVIRT: { - // First execution of this call. Ensure target method is compiled and - // patch the data item slot with the actual method code. - MethodDesc *pMD = (MethodDesc*)(targetMethod & ~INTERP_METHOD_DESC_TAG); + returnOffset = ip[1]; + callArgsOffset = ip[2]; + methodSlot = ip[3]; + + MethodDesc *pMD = (MethodDesc*)pMethod->pDataItems[methodSlot]; + + OBJECTREF *pThisArg = LOCAL_VAR_ADDR(callArgsOffset, OBJECTREF); + NULL_CHECK(*pThisArg); + + // Interpreter-TODO + // This needs to be optimized, not operating at MethodDesc level, rather with ftnptr + // slots containing the interpreter IR pointer + pMD = pMD->GetMethodDescOfVirtualizedCode(pThisArg, pMD->GetMethodTable()); + PCODE code = pMD->GetNativeCode(); - if (!code) { - // This is an optimization to ensure that the stack walk will not have to search - // for the topmost frame in the current InterpExecMethod. It is not required - // for correctness, as the stack walk will find the topmost frame anyway. But it - // would need to seek through the frames to find it. - // An alternative approach would be to update the topmost frame during stack walk - // to make the probability that the next stack walk will need to search only a - // small subset of frames high. + if (!code) + { pInterpreterFrame->SetTopInterpMethodContextFrame(pFrame); GCX_PREEMP(); pMD->PrepareInitialCode(CallerGCMode::Coop); code = pMD->GetNativeCode(); } - pMethod->pDataItems[methodSlot] = (void*)code; targetIp = (const int32_t*)code; + ip += 4; + // Interpreter-TODO unbox if target method class is valuetype + goto CALL_TARGET_IP; } - else + + case INTOP_CALL: { - // At this stage in the implementation, we assume this is pointer to - // interpreter code. In the future, this should probably be tagged pointer - // for interpreter call or normal pointer for JIT/R2R call. - targetIp = (const int32_t*)targetMethod; - } - } + returnOffset = ip[1]; + callArgsOffset = ip[2]; + methodSlot = ip[3]; + + ip += 4; +CALL_INTERP_SLOT: + { + size_t targetMethod = (size_t)pMethod->pDataItems[methodSlot]; + if (targetMethod & INTERP_METHOD_DESC_TAG) + { + // First execution of this call. Ensure target method is compiled and + // patch the data item slot with the actual method code. + MethodDesc *pMD = (MethodDesc*)(targetMethod & ~INTERP_METHOD_DESC_TAG); + PCODE code = pMD->GetNativeCode(); + if (!code) { + // This is an optimization to ensure that the stack walk will not have to search + // for the topmost frame in the current InterpExecMethod. It is not required + // for correctness, as the stack walk will find the topmost frame anyway. But it + // would need to seek through the frames to find it. + // An alternative approach would be to update the topmost frame during stack walk + // to make the probability that the next stack walk will need to search only a + // small subset of frames high. + pInterpreterFrame->SetTopInterpMethodContextFrame(pFrame); + GCX_PREEMP(); + pMD->PrepareInitialCode(CallerGCMode::Coop); + code = pMD->GetNativeCode(); + } + pMethod->pDataItems[methodSlot] = (void*)code; + targetIp = (const int32_t*)code; + } + else + { + // At this stage in the implementation, we assume this is pointer to + // interpreter code. In the future, this should probably be tagged pointer + // for interpreter call or normal pointer for JIT/R2R call. + targetIp = (const int32_t*)targetMethod; + } + } CALL_TARGET_IP: - // Save current execution state for when we return from called method - pFrame->ip = ip; + // Save current execution state for when we return from called method + pFrame->ip = ip; - // Allocate child frame. - { - InterpMethodContextFrame *pChildFrame = pFrame->pNext; - if (!pChildFrame) + // Allocate child frame. { - pChildFrame = (InterpMethodContextFrame*)alloca(sizeof(InterpMethodContextFrame)); - pChildFrame->pNext = NULL; - pFrame->pNext = pChildFrame; + InterpMethodContextFrame *pChildFrame = pFrame->pNext; + if (!pChildFrame) + { + pChildFrame = (InterpMethodContextFrame*)alloca(sizeof(InterpMethodContextFrame)); + pChildFrame->pNext = NULL; + pFrame->pNext = pChildFrame; + } + pChildFrame->ReInit(pFrame, targetIp, stack + returnOffset, stack + callArgsOffset); + pFrame = pChildFrame; } - pChildFrame->ReInit(pFrame, targetIp, stack + returnOffset, stack + callArgsOffset); - pFrame = pChildFrame; + assert (((size_t)pFrame->pStack % INTERP_STACK_ALIGNMENT) == 0); + + // Set execution state for the new frame + pMethod = *(InterpMethod**)pFrame->startIp; + stack = pFrame->pStack; + ip = pFrame->startIp + sizeof(InterpMethod*) / sizeof(int32_t); + pThreadContext->pStackPointer = stack + pMethod->allocaSize; + break; } - assert (((size_t)pFrame->pStack % INTERP_STACK_ALIGNMENT) == 0); - - // Set execution state for the new frame - pMethod = *(InterpMethod**)pFrame->startIp; - stack = pFrame->pStack; - ip = pFrame->startIp + sizeof(InterpMethod*) / sizeof(int32_t); - pThreadContext->pStackPointer = stack + pMethod->allocaSize; - break; - } - case INTOP_NEWOBJ: - { - returnOffset = ip[1]; - callArgsOffset = ip[2]; - methodSlot = ip[3]; - - OBJECTREF objRef = AllocateObject((MethodTable*)pMethod->pDataItems[ip[4]]); + case INTOP_NEWOBJ: + { + returnOffset = ip[1]; + callArgsOffset = ip[2]; + methodSlot = ip[3]; - // This is return value - LOCAL_VAR(returnOffset, OBJECTREF) = objRef; - // Set `this` arg for ctor call - LOCAL_VAR (callArgsOffset, OBJECTREF) = objRef; - ip += 5; + OBJECTREF objRef = AllocateObject((MethodTable*)pMethod->pDataItems[ip[4]]); - goto CALL_INTERP_SLOT; - } - case INTOP_NEWOBJ_VT: - { - returnOffset = ip[1]; - callArgsOffset = ip[2]; - methodSlot = ip[3]; + // This is return value + LOCAL_VAR(returnOffset, OBJECTREF) = objRef; + // Set `this` arg for ctor call + LOCAL_VAR (callArgsOffset, OBJECTREF) = objRef; + ip += 5; - int32_t vtSize = ip[4]; - void *vtThis = stack + returnOffset; + goto CALL_INTERP_SLOT; + } + case INTOP_NEWOBJ_VT: + { + returnOffset = ip[1]; + callArgsOffset = ip[2]; + methodSlot = ip[3]; - // clear the valuetype - memset(vtThis, 0, vtSize); - // pass the address of the valuetype - LOCAL_VAR(callArgsOffset, void*) = vtThis; + int32_t vtSize = ip[4]; + void *vtThis = stack + returnOffset; - ip += 5; - goto CALL_INTERP_SLOT; - } - case INTOP_ZEROBLK_IMM: - memset(LOCAL_VAR(ip[1], void*), 0, ip[2]); - ip += 3; - break; - case INTOP_LOCALLOC: - { - size_t len = LOCAL_VAR(ip[2], size_t); - void* pMemory = NULL; + // clear the valuetype + memset(vtThis, 0, vtSize); + // pass the address of the valuetype + LOCAL_VAR(callArgsOffset, void*) = vtThis; - if (len > 0) + ip += 5; + goto CALL_INTERP_SLOT; + } + case INTOP_ZEROBLK_IMM: + memset(LOCAL_VAR(ip[1], void*), 0, ip[2]); + ip += 3; + break; + case INTOP_LOCALLOC: { - pMemory = pThreadContext->frameDataAllocator.Alloc(pFrame, len); - if (pMemory == NULL) + size_t len = LOCAL_VAR(ip[2], size_t); + void* pMemory = NULL; + + if (len > 0) { - // Interpreter-TODO: OutOfMemoryException - assert(0); + pMemory = pThreadContext->frameDataAllocator.Alloc(pFrame, len); + if (pMemory == NULL) + { + // Interpreter-TODO: OutOfMemoryException + assert(0); + } + if (pMethod->initLocals) + { + memset(pMemory, 0, len); + } } - if (pMethod->initLocals) + + LOCAL_VAR(ip[1], void*) = pMemory; + ip += 3; + break; + } + case INTOP_GC_COLLECT: + { + // HACK: blocking gc of all generations to enable early stackwalk testing + // Interpreter-TODO: Remove this { - memset(pMemory, 0, len); + pInterpreterFrame->SetTopInterpMethodContextFrame(pFrame); + GCX_COOP(); + GCHeapUtilities::GetGCHeap()->GarbageCollect(-1, false, 0x00000002); } + ip++; + break; } - - LOCAL_VAR(ip[1], void*) = pMemory; - ip += 3; - break; - } - case INTOP_GC_COLLECT: { - // HACK: blocking gc of all generations to enable early stackwalk testing - // Interpreter-TODO: Remove this + case INTOP_THROW: { - pInterpreterFrame->SetTopInterpMethodContextFrame(pFrame); - GCX_COOP(); - GCHeapUtilities::GetGCHeap()->GarbageCollect(-1, false, 0x00000002); + OBJECTREF throwable; + if (LOCAL_VAR(ip[1], OBJECTREF) == nullptr) + { + EEException ex(kNullReferenceException); + throwable = ex.CreateThrowable(); + } + else + { + throwable = LOCAL_VAR(ip[1], OBJECTREF); + } + DispatchManagedException(throwable); + UNREACHABLE(); + break; } - ip++; - break; + case INTOP_FAILFAST: + assert(0); + break; + default: + assert(0); + break; } - case INTOP_FAILFAST: - assert(0); - break; - default: - assert(0); - break; } + UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; + UNINSTALL_MANAGED_EXCEPTION_DISPATCHER; + } + catch (const ResumeAfterCatchException& ex) + { + TADDR resumeSP; + TADDR resumeIP; + ex.GetResumeContext(&resumeSP, &resumeIP); + _ASSERTE(resumeSP != 0 && resumeIP != 0); + + InterpMethodContextFrame* pResumeFrame = (InterpMethodContextFrame*)resumeSP; + // Unwind the interpreter stack upto the resume frame + while (pFrame != pResumeFrame) + { + assert(pFrame != NULL); + pThreadContext->frameDataAllocator.PopInfo(pFrame); + pFrame->ip = 0; + pFrame = pFrame->pParent; + } + + // Set the current interpreter context to the resume one and continue execution from there + ip = (int32_t*)resumeIP; + + stack = pFrame->pStack; + pMethod = *(InterpMethod**)pFrame->startIp; + pThreadContext->pStackPointer = pFrame->pStack + pMethod->allocaSize; + goto MAIN_LOOP; } EXIT_FRAME: diff --git a/src/runtime/src/coreclr/vm/jithelpers.cpp b/src/runtime/src/coreclr/vm/jithelpers.cpp index c4f6c032050..3bdde3488e0 100644 --- a/src/runtime/src/coreclr/vm/jithelpers.cpp +++ b/src/runtime/src/coreclr/vm/jithelpers.cpp @@ -942,101 +942,6 @@ HCIMPLEND // VALUETYPE/BYREF HELPERS // //======================================================================== -/*************************************************************/ -HCIMPL2_RAW(Object*, JIT_Box_MP_FastPortable, CORINFO_CLASS_HANDLE type, void* unboxedData) -{ - CONTRACTL { - THROWS; - DISABLED(GC_TRIGGERS); - MODE_COOPERATIVE; - } CONTRACTL_END; - - if (unboxedData == nullptr) - { - // Tail call to the slow helper - return HCCALL2(JIT_Box, type, unboxedData); - } - - _ASSERTE(GCHeapUtilities::UseThreadAllocationContexts()); - ee_alloc_context* eeAllocContext = &t_runtime_thread_locals.alloc_context; - gc_alloc_context* allocContext = &eeAllocContext->m_GCAllocContext; - - TypeHandle typeHandle(type); - _ASSERTE(!typeHandle.IsTypeDesc()); // heap objects must have method tables - MethodTable *methodTable = typeHandle.AsMethodTable(); - // The fast helper should never be called for nullable types. - _ASSERTE(!methodTable->IsNullable()); - -#ifdef FEATURE_64BIT_ALIGNMENT - if (methodTable->RequiresAlign8()) - { - return HCCALL2(JIT_Box, type, unboxedData); - } -#endif - - SIZE_T size = methodTable->GetBaseSize(); - _ASSERTE(size % DATA_ALIGNMENT == 0); - - BYTE *allocPtr = allocContext->alloc_ptr; - _ASSERTE(allocPtr <= eeAllocContext->getCombinedLimit()); - if (size > static_cast(eeAllocContext->getCombinedLimit() - allocPtr)) - { - // Tail call to the slow helper - return HCCALL2(JIT_Box, type, unboxedData); - } - - allocContext->alloc_ptr = allocPtr + size; - - _ASSERTE(allocPtr != nullptr); - Object *object = reinterpret_cast(allocPtr); - _ASSERTE(object->HasEmptySyncBlockInfo()); - object->SetMethodTable(methodTable); - - // Copy the data into the object - CopyValueClass(object->UnBox(), unboxedData, methodTable); - - return object; -} -HCIMPLEND_RAW - -/*************************************************************/ -HCIMPL2(Object*, JIT_Box, CORINFO_CLASS_HANDLE type, void* unboxedData) -{ - FCALL_CONTRACT; - - OBJECTREF newobj = NULL; - HELPER_METHOD_FRAME_BEGIN_RET_NOPOLL(); // Set up a frame - GCPROTECT_BEGININTERIOR(unboxedData); - HELPER_METHOD_POLL(); - - // A null can be passed for boxing of a null ref. - if (unboxedData == NULL) - COMPlusThrow(kNullReferenceException); - - TypeHandle clsHnd(type); - - _ASSERTE(!clsHnd.IsTypeDesc()); // boxable types have method tables - - MethodTable *pMT = clsHnd.AsMethodTable(); - - _ASSERTE(pMT->IsFullyLoaded()); - - _ASSERTE (pMT->IsValueType() && !pMT->IsByRefLike()); - -#ifdef _DEBUG - if (g_pConfig->FastGCStressLevel()) { - GetThread()->DisableStressHeap(); - } -#endif // _DEBUG - - newobj = pMT->FastBox(&unboxedData); - - GCPROTECT_END(); - HELPER_METHOD_FRAME_END(); - return(OBJECTREFToObject(newobj)); -} -HCIMPLEND - /*************************************************************/ HCIMPL2(BOOL, JIT_IsInstanceOfException, CORINFO_CLASS_HANDLE type, Object* obj) { @@ -1320,7 +1225,7 @@ HCIMPLEND /*************************************************************/ -#if defined(TARGET_X86) && defined(FEATURE_EH_FUNCLETS) +#if defined(TARGET_X86) EXTERN_C FCDECL1(void, IL_Throw, Object* obj); EXTERN_C HCIMPL2(void, IL_Throw_x86, Object* obj, TransitionBlock* transitionBlock) #else @@ -1336,8 +1241,6 @@ HCIMPL1(void, IL_Throw, Object* obj) OBJECTREF oref = ObjectToOBJECTREF(obj); -#ifdef FEATURE_EH_FUNCLETS - Thread *pThread = GetThread(); SoftwareExceptionFrame exceptionFrame; @@ -1350,6 +1253,7 @@ HCIMPL1(void, IL_Throw, Object* obj) FC_CAN_TRIGGER_GC(); +#ifdef FEATURE_EH_FUNCLETS if (oref == 0) DispatchManagedException(kNullReferenceException); else @@ -1377,15 +1281,12 @@ HCIMPL1(void, IL_Throw, Object* obj) } DispatchManagedException(oref, exceptionFrame.GetContext()); - FC_CAN_TRIGGER_GC_END(); - UNREACHABLE(); -#endif // FEATURE_EH_FUNCLETS - - HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_EXCEPTION); // Set up a frame +#elif defined(TARGET_X86) + INSTALL_MANAGED_EXCEPTION_DISPATCHER; + INSTALL_UNWIND_AND_CONTINUE_HANDLER; #if defined(_DEBUG) && defined(TARGET_X86) - __helperframe.EnsureInit(NULL); - g_ExceptionEIP = (LPVOID)__helperframe.GetReturnAddress(); + g_ExceptionEIP = (PVOID)transitionBlock->m_ReturnAddress; #endif // defined(_DEBUG) && defined(TARGET_X86) if (oref == 0) @@ -1416,13 +1317,20 @@ HCIMPL1(void, IL_Throw, Object* obj) RaiseTheExceptionInternalOnly(oref, FALSE); - HELPER_METHOD_FRAME_END(); + UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; + UNINSTALL_MANAGED_EXCEPTION_DISPATCHER; +#else // FEATURE_EH_FUNCLETS + PORTABILITY_ASSERT("IL_Throw"); +#endif // FEATURE_EH_FUNCLETS + + FC_CAN_TRIGGER_GC_END(); + UNREACHABLE(); } HCIMPLEND /*************************************************************/ -#if defined(TARGET_X86) && defined(FEATURE_EH_FUNCLETS) +#if defined(TARGET_X86) EXTERN_C FCDECL0(void, IL_Rethrow); EXTERN_C HCIMPL1(void, IL_Rethrow_x86, TransitionBlock* transitionBlock) #else @@ -1433,7 +1341,6 @@ HCIMPL0(void, IL_Rethrow) FC_GC_POLL_NOT_NEEDED(); // throws always open up for GC -#ifdef FEATURE_EH_FUNCLETS Thread *pThread = GetThread(); SoftwareExceptionFrame exceptionFrame; @@ -1444,12 +1351,13 @@ HCIMPL0(void, IL_Rethrow) #endif exceptionFrame.InitAndLink(pThread); + FC_CAN_TRIGGER_GC(); + +#ifdef FEATURE_EH_FUNCLETS ExInfo *pActiveExInfo = (ExInfo*)pThread->GetExceptionState()->GetCurrentExceptionTracker(); ExInfo exInfo(pThread, pActiveExInfo->m_ptrs.ExceptionRecord, exceptionFrame.GetContext(), ExKind::None); - FC_CAN_TRIGGER_GC(); - GCPROTECT_BEGIN(exInfo.m_exception); PREPARE_NONVIRTUAL_CALLSITE(METHOD__EH__RH_RETHROW); DECLARE_ARGHOLDER_ARRAY(args, 2); @@ -1462,12 +1370,9 @@ HCIMPL0(void, IL_Rethrow) //Ex.RhRethrow(ref ExInfo activeExInfo, ref ExInfo exInfo) CALL_MANAGED_METHOD_NORET(args) GCPROTECT_END(); - - FC_CAN_TRIGGER_GC_END(); - UNREACHABLE(); -#endif - - HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_EXCEPTION); // Set up a frame +#elif defined(TARGET_X86) + INSTALL_MANAGED_EXCEPTION_DISPATCHER; + INSTALL_UNWIND_AND_CONTINUE_HANDLER; OBJECTREF throwable = GetThread()->GetThrowable(); if (throwable != NULL) @@ -1481,11 +1386,18 @@ HCIMPL0(void, IL_Rethrow) RealCOMPlusThrow(kInvalidProgramException, (UINT)IDS_EE_RETHROW_NOT_ALLOWED); } - HELPER_METHOD_FRAME_END(); + UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; + UNINSTALL_MANAGED_EXCEPTION_DISPATCHER; +#else // FEATURE_EH_FUNCLETS + PORTABILITY_ASSERT("IL_Rethrow"); +#endif // FEATURE_EH_FUNCLETS + + FC_CAN_TRIGGER_GC_END(); + UNREACHABLE(); } HCIMPLEND -#if defined(TARGET_X86) && defined(FEATURE_EH_FUNCLETS) +#if defined(TARGET_X86) EXTERN_C FCDECL1(void, IL_ThrowExact, Object* obj); EXTERN_C HCIMPL2(void, IL_ThrowExact_x86, Object* obj, TransitionBlock* transitionBlock) #else @@ -1502,7 +1414,6 @@ HCIMPL1(void, IL_ThrowExact, Object* obj) OBJECTREF oref = ObjectToOBJECTREF(obj); GetThread()->GetExceptionState()->SetRaisingForeignException(); -#ifdef FEATURE_EH_FUNCLETS Thread *pThread = GetThread(); SoftwareExceptionFrame exceptionFrame; @@ -1514,19 +1425,27 @@ HCIMPL1(void, IL_ThrowExact, Object* obj) exceptionFrame.InitAndLink(pThread); FC_CAN_TRIGGER_GC(); + +#ifdef FEATURE_EH_FUNCLETS DispatchManagedException(oref, exceptionFrame.GetContext()); - FC_CAN_TRIGGER_GC_END(); - UNREACHABLE(); -#else - HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_EXCEPTION); // Set up a frame +#elif defined(TARGET_X86) + INSTALL_MANAGED_EXCEPTION_DISPATCHER; + INSTALL_UNWIND_AND_CONTINUE_HANDLER; + #if defined(_DEBUG) && defined(TARGET_X86) - __helperframe.EnsureInit(NULL); - g_ExceptionEIP = (LPVOID)__helperframe.GetReturnAddress(); + g_ExceptionEIP = (PVOID)transitionBlock->m_ReturnAddress; #endif // defined(_DEBUG) && defined(TARGET_X86) RaiseTheExceptionInternalOnly(oref, FALSE); - HELPER_METHOD_FRAME_END(); -#endif + + UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; + UNINSTALL_MANAGED_EXCEPTION_DISPATCHER; +#else // FEATURE_EH_FUNCLETS + PORTABILITY_ASSERT("IL_ThrowExact"); +#endif // FEATURE_EH_FUNCLETS + + FC_CAN_TRIGGER_GC_END(); + UNREACHABLE(); } HCIMPLEND diff --git a/src/runtime/src/coreclr/vm/jitinterface.h b/src/runtime/src/coreclr/vm/jitinterface.h index 5d562dcbfbe..1b421ab3a20 100644 --- a/src/runtime/src/coreclr/vm/jitinterface.h +++ b/src/runtime/src/coreclr/vm/jitinterface.h @@ -1092,9 +1092,6 @@ void DoGcStress (PT_CONTEXT regs, NativeCodeVersion nativeCodeVersion); // means that the caller does not care whether the string is pinned or not. STRINGREF* ConstructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd, mdToken metaTok, void** ppPinnedString = nullptr); -FCDECL2(Object*, JIT_Box_MP_FastPortable, CORINFO_CLASS_HANDLE type, void* data); -FCDECL2(Object*, JIT_Box, CORINFO_CLASS_HANDLE type, void* data); - BOOL ObjIsInstanceOf(Object *pObject, TypeHandle toTypeHnd, BOOL throwCastException = FALSE); class InlinedCallFrame; diff --git a/src/runtime/src/coreclr/vm/jitinterfacegen.cpp b/src/runtime/src/coreclr/vm/jitinterfacegen.cpp index 1d55e308402..2190f295b2a 100644 --- a/src/runtime/src/coreclr/vm/jitinterfacegen.cpp +++ b/src/runtime/src/coreclr/vm/jitinterfacegen.cpp @@ -20,13 +20,8 @@ #ifdef HOST_64BIT -// These are the multi-processor-optimized versions of the allocation helpers -// that must be written in assembly. -EXTERN_C Object* JIT_BoxFastMP (CORINFO_CLASS_HANDLE type, void* unboxedData); - // These are the single-processor-optimized versions of the allocation helpers. EXTERN_C Object* JIT_TrialAllocSFastSP(CORINFO_CLASS_HANDLE typeHnd_); -EXTERN_C Object* JIT_BoxFastUP (CORINFO_CLASS_HANDLE type, void* unboxedData); EXTERN_C Object* AllocateStringFastUP (CLR_I4 cch); EXTERN_C Object* JIT_NewArr1OBJ_UP (CORINFO_CLASS_HANDLE arrayMT, INT_PTR size); @@ -65,7 +60,6 @@ void InitJITHelpers1() #ifdef TARGET_UNIX SetJitHelperFunction(CORINFO_HELP_NEWSFAST, JIT_NewS_MP_FastPortable); SetJitHelperFunction(CORINFO_HELP_NEWSFAST_ALIGN8, JIT_NewS_MP_FastPortable); - SetJitHelperFunction(CORINFO_HELP_BOX, JIT_Box_MP_FastPortable); SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1VC_MP_FastPortable); SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP_FastPortable); @@ -76,7 +70,6 @@ void InitJITHelpers1() { SetJitHelperFunction(CORINFO_HELP_NEWSFAST, JIT_NewS_MP_FastPortable); SetJitHelperFunction(CORINFO_HELP_NEWSFAST_ALIGN8, JIT_NewS_MP_FastPortable); - SetJitHelperFunction(CORINFO_HELP_BOX, JIT_Box_MP_FastPortable); SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1VC_MP_FastPortable); SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP_FastPortable); @@ -90,7 +83,6 @@ void InitJITHelpers1() // InlineGetThread versions because there is no need to call GetThread SetJitHelperFunction(CORINFO_HELP_NEWSFAST, JIT_TrialAllocSFastSP); SetJitHelperFunction(CORINFO_HELP_NEWSFAST_ALIGN8, JIT_TrialAllocSFastSP); - SetJitHelperFunction(CORINFO_HELP_BOX, JIT_BoxFastUP); SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1VC_UP); SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_UP); diff --git a/src/runtime/src/coreclr/vm/loongarch64/cgencpu.h b/src/runtime/src/coreclr/vm/loongarch64/cgencpu.h index d7bfc6b1228..989f3fd6bb7 100644 --- a/src/runtime/src/coreclr/vm/loongarch64/cgencpu.h +++ b/src/runtime/src/coreclr/vm/loongarch64/cgencpu.h @@ -229,6 +229,30 @@ inline TADDR GetFP(const T_CONTEXT * context) return (TADDR)(context->Fp); } +inline void SetFirstArgReg(T_CONTEXT *context, TADDR value) +{ + LIMITED_METHOD_DAC_CONTRACT; + context->A0 = DWORD64(value); +} + +inline TADDR GetFirstArgReg(T_CONTEXT *context) +{ + LIMITED_METHOD_DAC_CONTRACT; + return (TADDR)(context->A0); +} + +inline void SetSecondArgReg(T_CONTEXT *context, TADDR value) +{ + LIMITED_METHOD_DAC_CONTRACT; + context->A1 = DWORD64(value); +} + +inline TADDR GetSecondArgReg(T_CONTEXT *context) +{ + LIMITED_METHOD_DAC_CONTRACT; + return (TADDR)(context->A1); +} + inline TADDR GetMem(PCODE address, SIZE_T size, bool signExtend) { TADDR mem; diff --git a/src/runtime/src/coreclr/vm/loongarch64/stubs.cpp b/src/runtime/src/coreclr/vm/loongarch64/stubs.cpp index 920a2d892aa..e763157e07b 100644 --- a/src/runtime/src/coreclr/vm/loongarch64/stubs.cpp +++ b/src/runtime/src/coreclr/vm/loongarch64/stubs.cpp @@ -891,7 +891,6 @@ void InitJITHelpers1() SetJitHelperFunction(CORINFO_HELP_NEWSFAST_ALIGN8, JIT_NewS_MP_FastPortable); SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1VC_MP_FastPortable); SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP_FastPortable); - SetJitHelperFunction(CORINFO_HELP_BOX, JIT_Box_MP_FastPortable); ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateString_MP_FastPortable), ECall::FastAllocateString); } diff --git a/src/runtime/src/coreclr/vm/object.cpp b/src/runtime/src/coreclr/vm/object.cpp index dc469d2baf6..7285b85a9a5 100644 --- a/src/runtime/src/coreclr/vm/object.cpp +++ b/src/runtime/src/coreclr/vm/object.cpp @@ -348,7 +348,7 @@ void SetObjectReferenceUnchecked(OBJECTREF *dst,OBJECTREF ref) ErectWriteBarrier(dst, ref); } -void STDCALL CopyValueClassUnchecked(void* dest, void* src, MethodTable *pMT) +void CopyValueClassUnchecked(void* dest, void* src, MethodTable *pMT) { STATIC_CONTRACT_NOTHROW; @@ -395,7 +395,7 @@ void STDCALL CopyValueClassUnchecked(void* dest, void* src, MethodTable *pMT) // Copy value class into the argument specified by the argDest. // The destOffset is nonzero when copying values into Nullable, it is the offset // of the T value inside of the Nullable -void STDCALL CopyValueClassArgUnchecked(ArgDestination *argDest, void* src, MethodTable *pMT, int destOffset) +void CopyValueClassArgUnchecked(ArgDestination *argDest, void* src, MethodTable *pMT, int destOffset) { STATIC_CONTRACT_NOTHROW; STATIC_CONTRACT_GC_NOTRIGGER; diff --git a/src/runtime/src/coreclr/vm/object.h b/src/runtime/src/coreclr/vm/object.h index 663a4161f83..ca924879b79 100644 --- a/src/runtime/src/coreclr/vm/object.h +++ b/src/runtime/src/coreclr/vm/object.h @@ -493,8 +493,8 @@ inline void ClearObjectReference(OBJECTREF* dst) // CopyValueClass sets a value class field -void STDCALL CopyValueClassUnchecked(void* dest, void* src, MethodTable *pMT); -void STDCALL CopyValueClassArgUnchecked(ArgDestination *argDest, void* src, MethodTable *pMT, int destOffset); +void CopyValueClassUnchecked(void* dest, void* src, MethodTable *pMT); +void CopyValueClassArgUnchecked(ArgDestination *argDest, void* src, MethodTable *pMT, int destOffset); inline void InitValueClass(void *dest, MethodTable *pMT) { @@ -2510,8 +2510,6 @@ typedef PTR_ContractExceptionObject CONTRACTEXCEPTIONREF; // non-nullable case. // // To do this we need to -// * Modify the boxing helper code:JIT_Box (we don't need a special one because -// the JIT inlines the common case, so this only gets call in uncommon cases) // * Make a new helper for the Unbox case (see code:JIT_Unbox_Nullable) // * Plumb the JIT to ask for what kind of Boxing helper is needed // (see code:CEEInfo.getBoxHelper, code:CEEInfo.getUnBoxHelper diff --git a/src/runtime/src/coreclr/vm/peimage.h b/src/runtime/src/coreclr/vm/peimage.h index 0222f672b72..8315a217a07 100644 --- a/src/runtime/src/coreclr/vm/peimage.h +++ b/src/runtime/src/coreclr/vm/peimage.h @@ -149,7 +149,6 @@ class PEImage final HRESULT TryOpenFile(bool takeLock = false); void GetMVID(GUID *pMvid); - BOOL HasV1Metadata(); IMDInternalImport* GetMDImport(); BOOL MDImportLoaded(); diff --git a/src/runtime/src/coreclr/vm/peimage.inl b/src/runtime/src/coreclr/vm/peimage.inl index 70306304a23..3c12013030e 100644 --- a/src/runtime/src/coreclr/vm/peimage.inl +++ b/src/runtime/src/coreclr/vm/peimage.inl @@ -265,12 +265,6 @@ inline BOOL PEImage::MDImportLoaded() return m_pMDImport != NULL; } -inline BOOL PEImage::HasV1Metadata() -{ - WRAPPER_NO_CONTRACT; - return GetMDImport()->GetMetadataStreamVersion()==MD_STREAM_VER_1X; -} - inline BOOL PEImage::IsILOnly() { WRAPPER_NO_CONTRACT; diff --git a/src/runtime/src/coreclr/vm/riscv64/cgencpu.h b/src/runtime/src/coreclr/vm/riscv64/cgencpu.h index 38cd6c9b073..bfc84865123 100644 --- a/src/runtime/src/coreclr/vm/riscv64/cgencpu.h +++ b/src/runtime/src/coreclr/vm/riscv64/cgencpu.h @@ -237,6 +237,29 @@ inline TADDR GetFP(const T_CONTEXT * context) return (TADDR)(context->Fp); } +inline void SetFirstArgReg(T_CONTEXT *context, TADDR value) +{ + LIMITED_METHOD_DAC_CONTRACT; + context->A0 = DWORD64(value); +} + +inline TADDR GetFirstArgReg(T_CONTEXT *context) +{ + LIMITED_METHOD_DAC_CONTRACT; + return (TADDR)(context->A0); +} + +inline void SetSecondArgReg(T_CONTEXT *context, TADDR value) +{ + LIMITED_METHOD_DAC_CONTRACT; + context->A1 = DWORD64(value); +} + +inline TADDR GetSecondArgReg(T_CONTEXT *context) +{ + LIMITED_METHOD_DAC_CONTRACT; + return (TADDR)(context->A1); +} inline TADDR GetMem(PCODE address, SIZE_T size, bool signExtend) { diff --git a/src/runtime/src/coreclr/vm/riscv64/stubs.cpp b/src/runtime/src/coreclr/vm/riscv64/stubs.cpp index 5a2928efac9..c2e2d97e3eb 100644 --- a/src/runtime/src/coreclr/vm/riscv64/stubs.cpp +++ b/src/runtime/src/coreclr/vm/riscv64/stubs.cpp @@ -808,7 +808,6 @@ void InitJITHelpers1() SetJitHelperFunction(CORINFO_HELP_NEWSFAST_ALIGN8, JIT_NewS_MP_FastPortable); SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1VC_MP_FastPortable); SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP_FastPortable); - SetJitHelperFunction(CORINFO_HELP_BOX, JIT_Box_MP_FastPortable); ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateString_MP_FastPortable), ECall::FastAllocateString); } diff --git a/src/runtime/src/coreclr/vm/runtimehandles.cpp b/src/runtime/src/coreclr/vm/runtimehandles.cpp index 7a74f1cefd9..95a2c8c08aa 100644 --- a/src/runtime/src/coreclr/vm/runtimehandles.cpp +++ b/src/runtime/src/coreclr/vm/runtimehandles.cpp @@ -1143,6 +1143,50 @@ FCIMPL2(FC_BOOL_RET, RuntimeTypeHandle::CompareCanonicalHandles, ReflectClassBas } FCIMPLEND +FCIMPL1(Object*, RuntimeTypeHandle::InternalAllocNoChecks_FastPath, MethodTable* pMT) +{ + FCALL_CONTRACT; + + _ASSERTE(pMT != nullptr); + + if (!GCHeapUtilities::UseThreadAllocationContexts()) + { + return NULL; + } + + if (pMT->HasFinalizer()) + { + return NULL; + } + +#ifdef FEATURE_64BIT_ALIGNMENT + if (pMT->RequiresAlign8()) + { + return NULL; + } +#endif + + SIZE_T size = pMT->GetBaseSize(); + _ASSERTE(size % DATA_ALIGNMENT == 0); + + ee_alloc_context* allocContext = &t_runtime_thread_locals.alloc_context; + BYTE* allocPtr = allocContext->m_GCAllocContext.alloc_ptr; + BYTE* limit = allocContext->getCombinedLimit(); + + if ((SIZE_T)(limit - allocPtr) < size) + { + return NULL; // Fall back to slow path in managed + } + + allocContext->m_GCAllocContext.alloc_ptr = allocPtr + size; + Object* obj = reinterpret_cast(allocPtr); + obj->SetMethodTable(pMT); + _ASSERTE(obj->HasEmptySyncBlockInfo()); + + return obj; +} +FCIMPLEND + FCIMPL1(FC_BOOL_RET, RuntimeTypeHandle::IsGenericVariable, PTR_ReflectClassBaseObject pTypeUNSAFE) { FCALL_CONTRACT; diff --git a/src/runtime/src/coreclr/vm/runtimehandles.h b/src/runtime/src/coreclr/vm/runtimehandles.h index bf672af0f89..52dfc53d21b 100644 --- a/src/runtime/src/coreclr/vm/runtimehandles.h +++ b/src/runtime/src/coreclr/vm/runtimehandles.h @@ -125,6 +125,7 @@ class RuntimeTypeHandle FCDECL1(FC_BOOL_RET, ContainsGenericVariables, PTR_ReflectClassBaseObject pType); static FCDECL2(FC_BOOL_RET, CompareCanonicalHandles, PTR_ReflectClassBaseObject pLeft, PTR_ReflectClassBaseObject pRight); + static FCDECL1(Object*, InternalAllocNoChecks_FastPath, MethodTable* pMT); static FCDECL1(EnregisteredTypeHandle, GetElementTypeHandle, EnregisteredTypeHandle th); static FCDECL1(INT32, GetNumVirtuals, ReflectClassBaseObject *pType); @@ -143,6 +144,7 @@ extern "C" BOOL QCALLTYPE RuntimeTypeHandle_IsEquivalentTo(QCall::TypeHandle rtT #endif // FEATURE_TYPEEQUIVALENCE extern "C" void QCALLTYPE RuntimeTypeHandle_CreateInstanceForAnotherGenericParameter(QCall::TypeHandle pTypeHandle, TypeHandle *pInstArray, INT32 cInstArray, QCall::ObjectHandleOnStack pInstantiatedObject); extern "C" void QCALLTYPE RuntimeTypeHandle_InternalAlloc(MethodTable* pMT, QCall::ObjectHandleOnStack allocated); + extern "C" void QCALLTYPE RuntimeTypeHandle_InternalAllocNoChecks(MethodTable* pMT, QCall::ObjectHandleOnStack allocated); extern "C" void* QCALLTYPE RuntimeTypeHandle_AllocateTypeAssociatedMemory(QCall::TypeHandle type, uint32_t size); diff --git a/src/runtime/src/coreclr/vm/stackwalk.cpp b/src/runtime/src/coreclr/vm/stackwalk.cpp index 6cf15df25a2..6e903da8dca 100644 --- a/src/runtime/src/coreclr/vm/stackwalk.cpp +++ b/src/runtime/src/coreclr/vm/stackwalk.cpp @@ -2863,16 +2863,22 @@ void StackFrameIterator::ProcessCurrentFrame(void) { if (m_crawl.pFrame->GetFrameIdentifier() == FrameIdentifier::InterpreterFrame) { + PREGDISPLAY pRD = m_crawl.GetRegisterSet(); + if (!m_walkingInterpreterFrames) { // We have hit the InterpreterFrame while we were not processing the interpreter frames. // Switch to walking the underlying interpreted frames. - PTR_InterpMethodContextFrame pTOSInterpMethodContextFrame = ((PTR_InterpreterFrame)m_crawl.pFrame)->GetTopInterpMethodContextFrame(); - PREGDISPLAY pRD = m_crawl.GetRegisterSet(); - SetIP(pRD->pCurrentContext, (TADDR)pTOSInterpMethodContextFrame->ip); - SetSP(pRD->pCurrentContext, dac_cast(pTOSInterpMethodContextFrame)); - SetFP(pRD->pCurrentContext, (TADDR)pTOSInterpMethodContextFrame->pStack); - pRD->pCurrentContext->ContextFlags = CONTEXT_CONTROL; + // Save the registers the interpreter frames walking reuses so that we can restore them + // after we are done with the interpreter frames. + m_interpExecMethodIP = (TADDR)GetIP(pRD->pCurrentContext); + m_interpExecMethodSP = (TADDR)GetSP(pRD->pCurrentContext); + m_interpExecMethodFP = (TADDR)GetFP(pRD->pCurrentContext); + m_interpExecMethodFirstArgReg = (TADDR)GetFirstArgReg(pRD->pCurrentContext); + + ((PTR_InterpreterFrame)m_crawl.pFrame)->SetContextToInterpMethodContextFrame(pRD->pCurrentContext); + + pRD->pCurrentContext->ContextFlags = CONTEXT_FULL; SyncRegDisplayToCurrentContext(pRD); ProcessIp(GetControlPC(pRD)); m_walkingInterpreterFrames = m_crawl.isFrameless; @@ -2881,6 +2887,12 @@ void StackFrameIterator::ProcessCurrentFrame(void) { // We have finished walking the interpreted frames. Process the InterpreterFrame itself. m_walkingInterpreterFrames = false; + // Restore the registers to the values they had before we started walking the interpreter frames. + SetIP(pRD->pCurrentContext, m_interpExecMethodIP); + SetSP(pRD->pCurrentContext, m_interpExecMethodSP); + SetFP(pRD->pCurrentContext, m_interpExecMethodFP); + SetFirstArgReg(pRD->pCurrentContext, m_interpExecMethodFirstArgReg); + SyncRegDisplayToCurrentContext(pRD); } } } diff --git a/src/runtime/src/coreclr/vm/stackwalk.h b/src/runtime/src/coreclr/vm/stackwalk.h index ac93873c5fe..ca4afa3e2df 100644 --- a/src/runtime/src/coreclr/vm/stackwalk.h +++ b/src/runtime/src/coreclr/vm/stackwalk.h @@ -770,6 +770,13 @@ class StackFrameIterator bool m_fFoundFirstFunclet; #ifdef FEATURE_INTERPRETER bool m_walkingInterpreterFrames; + // Saved registers of the context of the InterpExecMethod. These registers are reused for interpreter frames, + // but we need to restore the original values after we are done with all the interpreted frames belonging to + // that InterpExecMethod. + TADDR m_interpExecMethodIP; + TADDR m_interpExecMethodSP; + TADDR m_interpExecMethodFP; + TADDR m_interpExecMethodFirstArgReg; #endif // FEATURE_INTERPRETER #if defined(RECORD_RESUMABLE_FRAME_SP) diff --git a/src/runtime/src/coreclr/vm/threads.cpp b/src/runtime/src/coreclr/vm/threads.cpp index fae6a001a01..0ff2fe966db 100644 --- a/src/runtime/src/coreclr/vm/threads.cpp +++ b/src/runtime/src/coreclr/vm/threads.cpp @@ -1330,7 +1330,7 @@ Thread::Thread() CONTRACTL_END; m_pFrame = FRAME_TOP; - m_pGCFrame = NULL; + m_pGCFrame = GCFRAME_TOP; m_fPreemptiveGCDisabled = 0; diff --git a/src/runtime/src/coreclr/vm/threads.h b/src/runtime/src/coreclr/vm/threads.h index 14c03a6a671..6a0b4c08f88 100644 --- a/src/runtime/src/coreclr/vm/threads.h +++ b/src/runtime/src/coreclr/vm/threads.h @@ -1218,7 +1218,7 @@ class Thread { void* curSP; curSP = (void *)GetCurrentSP(); - _ASSERTE((m_pGCFrame == NULL) || (curSP <= m_pGCFrame && m_pGCFrame < m_CacheStackBase)); + _ASSERTE((m_pGCFrame == (GCFrame*)-1) || (curSP <= m_pGCFrame && m_pGCFrame < m_CacheStackBase)); } #endif diff --git a/src/runtime/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs b/src/runtime/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs index 8fd6a33f8fb..40e99fcb0ae 100644 --- a/src/runtime/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs +++ b/src/runtime/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs @@ -338,6 +338,7 @@ internal enum EvpAlgorithmFamilyId DSA = 2, ECC = 3, MLKem = 4, + SlhDsa = 5, } } } diff --git a/src/runtime/src/libraries/Common/src/System/Security/Cryptography/SlhDsaAlgorithm.cs b/src/runtime/src/libraries/Common/src/System/Security/Cryptography/SlhDsaAlgorithm.cs index a0c4f584e6e..23cb59e1847 100644 --- a/src/runtime/src/libraries/Common/src/System/Security/Cryptography/SlhDsaAlgorithm.cs +++ b/src/runtime/src/libraries/Common/src/System/Security/Cryptography/SlhDsaAlgorithm.cs @@ -180,7 +180,7 @@ private SlhDsaAlgorithm(string name, int n, int signatureSizeInBytes, string oid /// public static SlhDsaAlgorithm SlhDsaShake256f { get; } = new SlhDsaAlgorithm("SLH-DSA-SHAKE-256f", 32, 49856, Oids.SlhDsaShake256f); - internal static SlhDsaAlgorithm? GetAlgorithmFromOid(string oid) + internal static SlhDsaAlgorithm? GetAlgorithmFromOid(string? oid) { return oid switch { diff --git a/src/runtime/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.NotSupported.cs b/src/runtime/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.NotSupported.cs index 1ea03be3e5b..7577333136f 100644 --- a/src/runtime/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.NotSupported.cs +++ b/src/runtime/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.NotSupported.cs @@ -13,7 +13,7 @@ internal sealed partial class SlhDsaImplementation : SlhDsa private SlhDsaImplementation(SlhDsaAlgorithm algorithm) : base(algorithm) => throw new PlatformNotSupportedException(); - internal static partial SlhDsa GenerateKeyCore(SlhDsaAlgorithm algorithm) => + internal static partial SlhDsaImplementation GenerateKeyCore(SlhDsaAlgorithm algorithm) => throw new PlatformNotSupportedException(); // The instance override methods are unreachable, as the constructor will always throw. @@ -32,13 +32,13 @@ protected override void ExportSlhDsaSecretKeyCore(Span destination) => protected override bool TryExportPkcs8PrivateKeyCore(Span destination, out int bytesWritten) => throw new PlatformNotSupportedException(); - internal static partial SlhDsa ImportPublicKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source) => + internal static partial SlhDsaImplementation ImportPublicKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source) => throw new PlatformNotSupportedException(); - internal static partial SlhDsa ImportPkcs8PrivateKeyValue(SlhDsaAlgorithm algorithm, ReadOnlySpan source) => + internal static partial SlhDsaImplementation ImportPkcs8PrivateKeyValue(SlhDsaAlgorithm algorithm, ReadOnlySpan source) => throw new PlatformNotSupportedException(); - internal static partial SlhDsa ImportSecretKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source) => + internal static partial SlhDsaImplementation ImportSecretKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source) => throw new PlatformNotSupportedException(); } } diff --git a/src/runtime/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.Windows.cs b/src/runtime/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.Windows.cs index 68f33987fd7..fea634c0e7f 100644 --- a/src/runtime/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.Windows.cs +++ b/src/runtime/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.Windows.cs @@ -14,7 +14,7 @@ internal sealed partial class SlhDsaImplementation : SlhDsa private SlhDsaImplementation(/* CngKey key, */ SlhDsaAlgorithm algorithm) : base(algorithm) => throw new PlatformNotSupportedException(); - internal static partial SlhDsa GenerateKeyCore(SlhDsaAlgorithm algorithm) => + internal static partial SlhDsaImplementation GenerateKeyCore(SlhDsaAlgorithm algorithm) => throw new PlatformNotSupportedException(); protected override void SignDataCore(ReadOnlySpan data, ReadOnlySpan context, Span destination) => @@ -32,13 +32,13 @@ protected override void ExportSlhDsaSecretKeyCore(Span destination) => protected override bool TryExportPkcs8PrivateKeyCore(Span destination, out int bytesWritten) => throw new PlatformNotSupportedException(); - internal static partial SlhDsa ImportPublicKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source) => + internal static partial SlhDsaImplementation ImportPublicKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source) => throw new PlatformNotSupportedException(); - internal static partial SlhDsa ImportPkcs8PrivateKeyValue(SlhDsaAlgorithm algorithm, ReadOnlySpan source) => + internal static partial SlhDsaImplementation ImportPkcs8PrivateKeyValue(SlhDsaAlgorithm algorithm, ReadOnlySpan source) => throw new PlatformNotSupportedException(); - internal static partial SlhDsa ImportSecretKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source) => + internal static partial SlhDsaImplementation ImportSecretKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source) => throw new PlatformNotSupportedException(); } } diff --git a/src/runtime/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.cs b/src/runtime/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.cs index 79da5d43d0c..04074a8c94b 100644 --- a/src/runtime/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.cs +++ b/src/runtime/src/libraries/Common/src/System/Security/Cryptography/SlhDsaImplementation.cs @@ -11,9 +11,30 @@ internal sealed partial class SlhDsaImplementation : SlhDsa { internal static partial bool SupportsAny(); - internal static partial SlhDsa GenerateKeyCore(SlhDsaAlgorithm algorithm); - internal static partial SlhDsa ImportPublicKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source); - internal static partial SlhDsa ImportPkcs8PrivateKeyValue(SlhDsaAlgorithm algorithm, ReadOnlySpan source); - internal static partial SlhDsa ImportSecretKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source); + internal static partial SlhDsaImplementation GenerateKeyCore(SlhDsaAlgorithm algorithm); + internal static partial SlhDsaImplementation ImportPublicKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source); + internal static partial SlhDsaImplementation ImportPkcs8PrivateKeyValue(SlhDsaAlgorithm algorithm, ReadOnlySpan source); + internal static partial SlhDsaImplementation ImportSecretKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source); + + /// + /// Duplicates an SLH-DSA private key by export/import. + /// Only intended to be used when the key type is unknown. + /// + internal static SlhDsaImplementation DuplicatePrivateKey(SlhDsa key) + { + Debug.Assert(key is not SlhDsaImplementation); + Debug.Assert(key.Algorithm.SecretKeySizeInBytes <= 128); + + Span secretKey = (stackalloc byte[128])[..key.Algorithm.SecretKeySizeInBytes]; + key.ExportSlhDsaSecretKey(secretKey); + try + { + return ImportSecretKey(key.Algorithm, secretKey); + } + finally + { + CryptographicOperations.ZeroMemory(secretKey); + } + } } } diff --git a/src/runtime/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaTestData.GeneratedCertificates.cs b/src/runtime/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaTestData.GeneratedCertificates.cs new file mode 100644 index 00000000000..2485f0ff3d5 --- /dev/null +++ b/src/runtime/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaTestData.GeneratedCertificates.cs @@ -0,0 +1,13800 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Security.Cryptography.SLHDsa.Tests +{ + public static partial class SlhDsaTestData + { + public static partial SlhDsaGeneratedKeyInfo[] GeneratedKeyInfosRaw => field ??= + [ + new(Id: 1, + SlhDsaAlgorithm.SlhDsaSha2_128s, + """ + BD7334288B7F4351AC28A56B487ED3D237EE5E8FCCB12F2E19DFC2B8DEE98F6F138D1ED76F1B6639224253F9A9EFEBFAA54680EE67332BA9B84AC03526C035B2 + """, + """ + MFICAQAwCwYJYIZIAWUDBAMUBEC9czQoi39DUawopWtIftPSN+5ej8yxLy4Z38K4 + 3umPbxONHtdvG2Y5IkJT+anv6/qlRoDuZzMrqbhKwDUmwDWy + """, + """ + MDAwCwYJYIZIAWUDBAMUAyEAE40e128bZjkiQlP5qe/r+qVGgO5nMyupuErANSbA + NbI= + """, + """ + MIGjMEcGCSqGSIb3DQEFDTA6MCIGCSqGSIb3DQEFDDAVBBA9TpVD3G5e5tA06y/t + PayHAgEBMBQGCCqGSIb3DQMHBAii1ZbSTmOvqARYRWNqN+6R0eDd97ZY6am7X20A + DMRVPCOnRttB5/WfY6jFx5WYnPE7k4T4+14SEzcCS685a6TyYLQ4KhWhOGwuvxKw + 4ERKirM8DRwhVg1umcebM3AZNU/cIQ== + """, + """ + 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 + Nhw7iWpd1w== + """, + """ + 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 + """, + """ + 9840BB4284C5CA5DB8EB9F295C926603FBFC593F + """, + "PLACEHOLDER", + new PbeParameters( + encryptionAlgorithm: PbeEncryptionAlgorithm.TripleDes3KeyPkcs12, + hashAlgorithm: HashAlgorithmName.SHA1, + iterationCount: 1 + )), + new(Id: 2, + SlhDsaAlgorithm.SlhDsaSha2_128f, + """ + 3918D143056E208C1BB52A34BD13B677F92B5D487206C9F7F9525584F7FE1DA396EBA85CC550FA075E7F467D84384F0C13FB07C0876ED288B3A0C964A0EB588B + """, + """ + MFICAQAwCwYJYIZIAWUDBAMVBEA5GNFDBW4gjBu1KjS9E7Z3+StdSHIGyff5UlWE + 9/4do5brqFzFUPoHXn9GfYQ4TwwT+wfAh27SiLOgyWSg61iL + """, + """ + MDAwCwYJYIZIAWUDBAMVAyEAluuoXMVQ+gdef0Z9hDhPDBP7B8CHbtKIs6DJZKDr + WIs= + """, + """ + MIHCMF4GCSqGSIb3DQEFDTBRMDAGCSqGSIb3DQEFDDAjBBBoWjB8IDv4APhGPQTV + oZ7VAgEBMAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAECBBACu/ibonxCOUkIjhDZ + vKBPBGBpSE35PH0IlFJCrSpY8ufrSkcqZ3OuO5wkFwbwMfvq6TS2NrfS5IcAuPx9 + 13jZdjlh29a0UFYI1ZjRkV9M46Yi9+bS1Cl+zmwN8KSq4lUpTU6APPmgL41FtBtI + VKhfhFc= + """, + """ + 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 + B1wHU7Y28vDN5DJyY81C5TEZfZqJCvE= + """, + """ + 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 + PBn4xC1PsSVo/Wi+4EW3LezLtfCJCUK11njm/U+/y/GJZX9/w15LdsL0nsdThgMY + QXx/r3+IzhZPeg4fmQvvwgJEgPMF6po4qdKYKPLuxim9nKGSCtvoQ0xqYmXLNF2O + XcZ5Gx5H0l9FPN/Qd2bpJr4acTn0ZlYukEjfZ62V00Rq7dbMcu8YH5itbnZWym5n + FAAaIcMCoJ61KcBxr8hK/Pb9ssILaLioyRvsFO7rbRrpL6iE18FtsCRNuKHvuf8m + bPKZiyoLYYgsdawILzQtIm3zM9V+DtMTf7fIWaG0/zKQ4rTWLc1Y4yVpz750jN1A + qB/CiqlqZnGqfag8Hoxu/RvxTYfzh7srHkD8+vRW19kJh/uTfoNkmvYezQ22B6N5 + BrfXVXKMgOA9/AeRylSiqfzT7GvysHV2Tr2NTqhpgTKuxyUzLwMg5fQyv8ryDaDR + COIPBGuuV0dJZFlkVzMzwrllMVI4FNBlAj8rsvT53u0HeSYXL6I4Demx2TzgHmQT + 7LbdqL/1Yr2gJOX4wYjwkEKvUjW4KrY9MdH7hezqH4AXJ2Kwfh0uJyvPvdkbtnks + RDg4GbsrNZmEkUJay1ZdC3V/OHnBdcO5pZH3gyQWWlqsVeAN4F3x7vuhsEBR9c94 + TRfLbuSFPpR7ir7tWIbf7iaUrPEPL2MeL5XHXDz5hhMyATVQ3BEabGW64skUxljD + SM1FlYRiJM94zfVZ6UbEDCpyfncjVksZaDrvWiia2jpUZ55XbLnbb+SqeEaooocC + 7nnxsTGa/NPjOSLLeCR8tO62Idg2kfJbfYc0ThtEjvxQhVq/gOTZfPhK2CRH/0sb + xSdyoSJ0C0riOGZJ8lghJG2szAvKbtuRhpVcggbyFWkPaysIkSgbRQywVJ6uT3EF + nft65WmhwucupkxWDsjfrysytRpVQm2N4RemJvjdmbSATkXMYRv7hbwfg7t7ZuoO + jUHXx4zFfugMSb5pWe6m/B1U8k2oxnTXNlKqr22CH1I2AHKoYjc91QLMgjB2CI3z + ATgSrzg/+nq1uT2g/J90qmHkB1GV0nZfrxq5mhIaRVYnlNVzIe5v7Bvse0IdzrlZ + xqmxVZQybutM8hpRocMv1wlKGzaIwfpNtv4EceTVZw8H6hcIBSAPDMBJqYwJwnA7 + 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 + BHeOvwEx/Q== + """, + """ + 7BBD17650D3535742F590B78F557312D4451683F + """, + "PLACEHOLDER", + new PbeParameters( + encryptionAlgorithm: PbeEncryptionAlgorithm.Aes128Cbc, + hashAlgorithm: HashAlgorithmName.SHA256, + iterationCount: 1 + )), + new(Id: 3, + SlhDsaAlgorithm.SlhDsaShake128s, + """ + 3D216B8172DC19DE1F70206C847FB36A54AABA39033E1CD3BD3BEC1018B0EB64E41356B27B9F05C83C90B51AFDEA4B9D87BE5D5A10137F531B5300D44B8FD41A + """, + """ + MFICAQAwCwYJYIZIAWUDBAMaBEA9IWuBctwZ3h9wIGyEf7NqVKq6OQM+HNO9O+wQ + GLDrZOQTVrJ7nwXIPJC1Gv3qS52Hvl1aEBN/UxtTANRLj9Qa + """, + """ + MDAwCwYJYIZIAWUDBAMaAyEA5BNWsnufBcg8kLUa/epLnYe+XVoQE39TG1MA1EuP + 1Bo= + """, + """ + MIHCMF4GCSqGSIb3DQEFDTBRMDAGCSqGSIb3DQEFDDAjBBDiIMsFSIx9vFhooI2W + EntqAgEBMAwGCCqGSIb3DQIKBQAwHQYJYIZIAWUDBAEWBBBP18dmoJfpUMom/EnY + KFEQBGCYhNAKaoN+7KK+7FCXCiRtJDeOcEkhK5wXPdVI2Xt4ZtcBzVo1CjVyO4uA + WJS6vLP8b9vGzyC99kb7use9IGev12VUfycUJiddzB1+4ObpxSIH/Kk7Rqt8Lk9q + 86RM1ZQ= + """, + """ + MIIf5TCCAR+gAwIBAgIUMxOdhqCAckn6ruK942Rt04fGJ+EwCwYJYIZIAWUDBAMa + MCUxIzAhBgNVBAoMGkZha2UgU0xILURTQS1TSEFLRS0xMjhzIENBMCAXDTI1MDQz + MDIzMTQwNFoYDzIwNTIwOTE1MjMxNDA0WjAlMSMwIQYDVQQKDBpGYWtlIFNMSC1E + U0EtU0hBS0UtMTI4cyBDQTAwMAsGCWCGSAFlAwQDGgMhAOQTVrJ7nwXIPJC1Gv3q + S52Hvl1aEBN/UxtTANRLj9Qao1MwUTAdBgNVHQ4EFgQUUd75O70RZsQkZkFcvpW0 + 1hMQmNwwHwYDVR0jBBgwFoAUUd75O70RZsQkZkFcvpW01hMQmNwwDwYDVR0TAQH/ + BAUwAwEB/zALBglghkgBZQMEAxoDgh6xAN+o9E03s4tujF7ZyrXyCnzw6N4sNJnm + EVp/LfMMDKICvHDodR8lIb/9YbG/7XLRt9u0K+3ZtsXY1Hp3/jDCO+CIy0QtDpT4 + KSNlNU+i1xkO3saUi14LLnt8CsI+/MRikMootwkBnSrc3GESCmGukHJfASA40lyT + WBd1nodwyBtQYERoMGlfT+8O0REaAM85N9tDxfaJ9y4RYW/CLnsY6gTg75Y1pCht + l4R530ei2dvalkz0DRHnj3jfYj+24tLJtryodd22df213IS37uL6qTJDKtfhZqh1 + 7UQW8ywAKDyDQIiB/YEB+Ij+XfN68dpk3LJUcwtt/4UDlkuPVHcFbB6oPwVYbyqP + rem69NFAZKs/fl1KthWrsDz41suG4voPL+8nltkCBCqcBS34kJVMEwul6q6i1+OT + hRLcMc2AGHGSYAH2tKy9xvWeicc7NwWdqWBnZKrP9t/9mOC6vvEMir1gP0+V6j3t + PgHlwUeaIaEKV1u1Ta/wMcJWtgJb1EM404Hhus9bTLklgP7Me292AHdFqIoyBHkU + XybZjGNxic46yZSoZ3yj0uOGEGfnREDz309otOI/ZayAOtGCJKye1q+v7bz8CL+i + IM2YXLDnkNp1ysf7o029EASNON7rlZdJcuMkMtcnLQeyq4tnNqqh8qbCBAYo+aDF + o9FCeCLngKjwOSrEDNBMUmx49hiYO/r9O2ZH+jAw/4+8zlFLq90O4+P2svgfmLpL + OS0vXXTmgFcDPdMfYl3PLV+UrCoGt3orZWFZDGyDNOaT3M06iNjEuTTCqkM0Ae0i + FthmtMmVQtuYz5Ztv/JwP1cOByN7xyYZeSqRWfkxZ4FJFXYiExUduONf07xDT9T5 + iOyfdP0m2ZwmHRLqNKMKOQ7J1dR/driW4baPhz4gMlnJl4Uag7LUs+TQJuCo76Yg + v6mdazcb17ZCjU6EdpxIyGTpGLUB5PMa3JPFGy4po3IdJZ69908NgzlKa356ilLn + Z0MRSWc6bHuGxt1qsi/6uUTCTpK0WJF28TvLc9oCsxGZPDQ8uz10BnMrYXtTBLtC + h/uUsxBWDOERqqgPkasTf9TkAQYAj+3/Xn+wU+ndRqYIQ2DpyuW881+24qIZDKjd + lsjpOCb8JjlgXKxNSVBfkYxVf/Iaus947eLpkkeNt/9Tuo8Z2QEn744PE6i2YVJq + 0p/+pyBCGo1K7QAvjuT0Bvknv3+J07GrmJx/njfqgFb64w/k5DBw+UisbLCNhWoF + pMT0vhqIknNNnS17u9acOmm/DKIxBShD6EaPiygbcgkWqyDmbN481jSyzIpS5ZvB + KQ8md8lGL4PjTyka5ItO6VPDGSRiumbVvleWRfvem5vvVDRzkUWaDET2WDczQdNi + 4YAEA7mqpIdnDLMo9pyG69lOgHbSc0Cmi+MSPGp+F96v9S2AgTHIt82QDLWB/3ZF + G+7Cc8LqSp5WBydqoRzeTdh50FeziRvOq1i4wehnMZO8m5P+5EgTnm2AIAcyYvqy + a3oPUE4wrsMghSlqEgWo+m63V8r3ojPgrUolzl6Fft/1CF9+U8OOkD2d6P61V4ht + Rv8Z9O4sXDMT4xKLU3qtVA9D2HWqKSKsJYczDSLV9kWw9RHGTcIa5NGLc4AnfWXk + UW9nbY5OySs7HkYO8kisGWfRRS8nf5VITmrr0iS9LmsGHxT0XKM1eAPwDa8QC/uQ + ioZwJgF+QKyVt2GJ4S3/BZ+rPPBc/QExBRKvRaeK+deH/HuxkOEOkc0+Qa/OsBgB + O0jgge9jrpLYABjI0jIYGylNGxqBzANubw2mQWI/54T3J4gbipLYw97D45XxRkrB + lISxOqE5MSwHc9BMs/0v1V7cMYmw6BlLHtOWhlCHnu+qyExXxG8rLg7YilFtQdFW + y0+q+CI38ODyFHFgE8k7txrD3fQgfd8pcmi13/sN+xxq4FTfZf5zk+aD/FM+5iE9 + rY6mcStirzLjUNYrqYXlRsdKd/9SDtZiWSSf+v417Q03dr+Outy3mhLkPG9q3QrZ + x9LbtT0w6MadoktdgmdCdXoX8M1hgGmzwaCfhDbaMz8HPCtK9nqPUi4x7KGGD4mM + OmPrdpPvOXy/PY6AitBFEGCtQgLyaYgVYsTRGhpnQTwUwwotZqVNwHORgRfJkSM7 + auyONX4mEoRupQVHeuAvnDXg8nJ+vdYMAkjZRu9LfwZ4TJQb6QLQAaXi7dLIUW97 + VPDwQACEctl9i+9t1NnSedO/Dr7BpdHbEiOZGgABbwAaPauv5x6KIk8CUvaqZj38 + boHqypQ903AiF46mxUbo/3Vk4oy1djTHkdBk1QRlPHQkEK6l3FHpb48uUG2r0CUo + stqsZv8skUYrXTDnuvvsyHJPWfwc0TRtY3xJHQDC99DYYO3jgLtlQBZcuJ0j9CK2 + /2K6HlnMIoc4U0ns3I0Pp5FrOeXTmXMLkJ6ENx97EKhhD+xYl/pwI7rQfQvJ8kF1 + Ln3cKiYhe3U7vjv7X5KCkmn8sAWhFCJilvM3lFFHmUIdjfxtLVHyf3xXGSJM0Izr + ZoIIzaWJ3nvHW7LRl17DftK8Q21ssvonOA4tsz0vjoSBGKAxw2soLjvju3jvhEcx + E3AmUfTR0iblEk3tEGdsVCAd8wPL4W0A76MwPEUkMm/wl94fv21Dp1FVaUQVP067 + iTviCfhnTU+VXx26Xf5uaQynPpLsEVzRggFLGPIZS3FowvWeANq9P0gVf/r3xCq9 + KlIBdVNbT7ccjusBFEbxOucgv3N/HdsAQT5AT1ToXUNQecxv0LwDKGxLFCZ/Pjl7 + o+S/iVJfVpjDJ9iXVLmJfMQ75Upvqaq3cuDWjxb8Kul52susL0oFLrws5lJ/bikp + 2SdW5FJl0jNxXz2vXaOi6fDUhelD1Vt8Afll8ZoQLr6XQpmCEeVwupgez4dFNWgX + AqrWwW4cHaE0YKDoupAcwyF14yE89OSaLqYxkhM7xQ9XVdfSJxWNgYD3Ora8PtSx + QPJPtqk1/5zb79ijY7slz0c/bdfOGoll6kVWYPXZwwzEUfWpL6lsu3PabaVx6H+o + 09c4wqoFLd7nYo6Y+s93poA9JjgwPeX7E7JEyZ2eztoT64hZJSWv3eNp04yV+gdT + VMhzVe/wCp47GEUA2/pmtMLeukQxJHzWsiV8VXyniQl6gEEFzqg/4y2S3Bp1aIhr + SkNIbedtOHX0wxrxRysejXrhPIyabkKT+c1Ws05Q6W6BmzLeuHoVQlabF4sMMRP2 + vNYDVTD/4s50AocZH0lIG8t2kxif/OOD51EiMD7u8PYZq6Pdx0HitIKxzJCW4byh + cCnm9H9zcTQhmietAdL3S+2cHWfefxr5Oid7uKUfC+QdXLfq2il9iagGqs/vr3aV + xnQPCza/nbQsii55Kaqu0ww0cFcrL3o0P6wKYJ+9oa++c1kP6zqxQtu9OZrtLHG/ + s1a8aAmG8wNyaODKdErplop6XHFq3dM+i30LjykkAVOJ7SOX+TLe2w/b1o+AbqhM + MqdumFwd+Ws9biYDM4wS8lFCAtOipOs+rPtR7ot1iT+eevivZS+Z/y8VJjQu3pWc + ZvqfQdMZc2vAeapJMLglzs5F0myUqgPkc95XAyoN/jaTFd4o86cH6CqEyeQQFo6R + UEOTacQGriaW6UStSxTFs5mdc6ao6bwNuKEa/D9qsg/VGPejrejFd37PC7F89+D1 + G+TQohf/mQEkPjBwdzhK7DwJD21C35/DAsifQuQ9YOnT0LM0PjFwRoZi+OvgAIxg + c04Abs27nowUhhQuEp7ps9g9HIkY6tlvi/Gzbvr/F0Q8LCoNdSAS24ImLeX3CZis + 80gnZ92e1pd6K9swXFqK7F/2DUJVgBMd9SOzualR9uS9sQPX37uFo79XfCi2ErFU + zfawucXrPO/IrPpc/rbwxoail8BQE+4HUxayNHvS01k5IIp3lV2PU4hnLeGFfbnk + mmlEtyk7cn4OS1x4kfh7fiJKnVSIqRcJYq+iY6dL5ac/BFhsEQrj7sfCWJc0gHyw + EbmV90dAj++oSp3MoHbAqK9TX5m8uCbBlTIZnXgMeDsObweRku7LKmRYF2WhFHCU + bGxZGSRKJ1yyC3OhpUgE7hDUa4IG4+5FXFKVDpb/+gM0+yop+ixMuzsNRcpdY3+3 + jd2LFasBZIot72jn3YtLag8qFpNFrK9/OND+fk2z72qfk2xmDA2PkVkRlTMVsJnV + EUX83G6ijHAEGFvt4VoZ+nptgk49dRKN3RpnUnaeCtH/Xl9HREa6O0bI0VZ4E9Xr + TPD/3WHE5KtR323qamO49sx2xxi1BTS5XHe7aBL/NjrovcgAQUiytFpeQ3Pe/O1x + 1GoXWF+T9pRaC2LUzlFHCChsDgWC6NKqY+zBD2CiyoPb4xKmhA7CCXWbSiy02j8A + qti+6TGAd028G3glmfWmj7+cvx16SN5ivOGHfLeFeP9wQmW7B8ZXfu6QmBkKsz1N + ButkWWcP+0Y8rW0US0stC2d86sV0Tdv660hDO+kgwa6ZIPBaEJVyOmQHJGMPbOix + QC78EWDPPrkynHh2DuQU8foed2e0gqSxNwJw4IkLIEvnlHlW3Qvx3c24Pm9pBJKd + /gAq0F8VCHy5cAOTaXhw0mrx1h5m0ittvnfI8ddS/i58FkIZaUgLjKXNZyG7jUxj + 6hgw4gIjVfohJEECT6qGHHdmVGjS5GDdLAzu0dI2kWIfGb4v8qcP5ZADJehOuHnv + TtkXnnGj/xbWYIbVIun8g5E2gG3bTLTJYjTNAmgKeHx4ggiLuEc0fV6VwsukcXIy + xKyL4FQDzbkpOEWQ1EZmKkdKXSWQ/QiaXosh/EWgHROiKjQfA6iY0+YhsV9x2GJ/ + AIGlQ2NIeKvfBof5i+9v/uIZU5txc1NLi9uMkYEdUCWKUZ5uKBrL+EJzZ8J5lPGQ + YjIqJmtg2eakiYg2YS4AD6sI01WIzuMU/NASAvMIufRuA+boxvZGTiHnQVW39SMl + smojuRirc/jHl9PGr3U/anW7jsgTXZChwSVafxBX+ng19EZfa4WZTPQ95OdeD/RY + U82tEq0G0FnFHguxy7VTrgVm8gaP5RXvwwM6LYkhGIqipl9Ol3iH4isA9vRd7PEt + Tv1/qq8bpBl5uzj6vHZ6zdVX9j3LxmWWIidzgfR1DhhoQ5WRG7H06qA3ReCtQ0ro + uWvdpyC/5PDXp/4l2dcgdyox9hOdRthRJzPxuDZyERTGbyP4VlnHaLd8wqsd/k68 + thrazuYyxhS9a+Oa5e7uL40tnJzgA2u6RiTB3vL+QffPPwiBgWQb5+vWHVSATjHe + AztGs1ARIzndjsQlmLH8Hhhbeo8nbXACe4ZfRA7moZNZi8YfD3JdZ9hLmvSi+isv + +9UW6LOUJB11LB+utnGV74lEeiiMfYfW4IU5+voC+XIkLHm/Mic4uZ0xkdAPaZCk + vNM5vqVe9EOTQI+WX5Gqio42GUdA1g/IGVutUTMx//7BPUkQSNjoFAB13DFI1Msl + 1eickaNvK6+aHYv/mzGeBUs01phURgZC3EdwGuc6d629iQhzh0op3Uhcj0BfEGI6 + t1SZAINd306oVpB+r+rLEGtgfz5rq728aNawKm6pfnpp7IF8y1XhsaYBls1E6+63 + MMXbHFRJiZ4eJf3gw9x2rwWVQAGTWzqXico8us+DNcxOuyrfTO6tyZno6bB748Hf + lm+zc3YygjGJ9YWYpe3qsxvXgYG7sSSLSzOb88XYz9yWYJLAtb6s6idMlhNgXV7m + g9K3ZlITKNWuVHlYAi496USGqKtUKyCwyYcJ0HWkx3K4spKBJWmlSPm6UImtoh5I + vIOchSf7rROYWEGgaWzmnY63gH9t9mciJPM+OJtYwyGllqck/NYyoScKTbe4PQG9 + pQT6XV7FcrnyNaGoqEjl3Abkf/WgOBgA9QQslleTnognRW0tLQ0j/FcYWEbJcBYp + APQ3zdyADjWuLTq6OhtSt42MqkYOz5478/UDnI5ggbvJkItxN+9CmM2WN7cud3F4 + xncbVABbvpZNWbb5uTfnrjBjC2QMo7holQZNgBDEizDl2beAuHpk7hPAczxZ1t89 + f1Q3asp/JY2Sl/Z+C/nw9SdhZsuYRfwRhqGCbhEVF2hW44hlljMPs6xR2WbBkW1m + cOq3U/0H9qghBEMon4fS6vLodfW/j5z7E7HbqXpdexpWygzjYXYNso5BXPMc7tur + hYgG3Ubs4/Uh/O0SCI1FrRU05qQOCBrn/bwbS3JGB1qbajAHrCZFyuAPmfTXOyww + MsC7UrWrtgj1rhiKZQrKshBn9paWSKv9GS6L3KcQBOcw4CDJiEiFrI3WJRsPgyVk + zP1cx8mEkXDfxrmoqQOw3CcdqHQNuOyc+WGqQoiMtAxF9aNEST0KNC0sA+Fl8/Fb + 80xEem3Qj8DYFryvefF/pXTcWa8ln3pd2EfZ+dzFpa3ZnKYCrolFGxS9JWnn+aUc + Yy8aULf4mAJQSonYWgylh+wBhcQpzwF3yWTkwbzrgTtxz8rSSScuQxr+xuJ8zPIL + NsCJeIgvlEQBsbjpba8EpbO8rqrPBl4uyRPOUAAuIBLwD2tmTiPudWWmrDLrZ13f + TwFwwxLXrUConmQfpTUgm99p+IRs3bAfIU3VSaTBNlioXPipLNkTwT7XMVUkikHm + VyBQeA+gL5Nf4eV2gByhSsReh6UOdNCZj7izrhOMqMJmnqGkT6rDQgU++E20G/3o + Cc6W41x30EAf8/xNhf6P8HpojVJC1ZJG33oENDAcrW48XuPt0csDnPPKGtsKaFX6 + 8fPfxsLOLOhSPSYjCFDf2rW1XjY72hxofjFqyrK6pxQ43hJoBNmwn/J7vFt6qHi/ + DMiqaW0TyoiwlBvrqLv6F+1UyuqOXoiD4yGFzIkp1mG7e+9UmHCDxTUPN0Tf5/Os + gNIJTmYZCQ1bHWCPeOIJtR5oSeLuBAYrYE4Ef1PRMd+7Kv4AYqIynUeuXYA1k4bG + AwUMr+utNAqvrxlfgaBZC5KhG7km5f4wYAgOwLoY/TvOZ20OW+j44emlWOraEd37 + bGbNQw7Jg6Ka/QqnKdS+DrL3sWdR8zmfqAqsOCgnbMvcHc/EEw/hAQ30oc4Qdiwj + QWHi+Tv4sj7An8tSJUgxNED7NH2uTgirSHBmt4BwU1dwtoN0g221dpbSOz+irK4O + MckCnvrweKo7Dhe83J4f1e+2uRr/F4HdoCguIeSQQV0Dmk6BhnBxoLSTFmQcdbxg + O8J1o5GU0iqNOODeDxboi6UK2Uw7yRCe8IqLRtf1T+L5UkVytVngVA5rk97MD42i + +EmAqPdIwx1QDIhU4ZWwyvy78ktvNz6uZAOwJmdyIfgCPqSPp5uN5xrAGofqPqfF + Ad2HTjOVHK/sfJt3lh3fvEy8+AalbsXTM8ZTo3wZ6vwAmXpURCaQSntnrRGOZDV1 + 7qjEGawT/Ez2DcrDxWd38+FAWilJUPBZbhfUObkYP6zV06Th/UIGURs874h3Qxta + nZ+oH7sNA0de/+wb6nGEUsHC3qQM8sd+hoS4qNgI7cm1GDe9HyBaj6l4Wi3eE/D4 + ZdqyJ+4VYDH57sKipVhKbLYAYqWhTTX7lZGMQVPQDU7tS5Kymc/JFEFmf2jR+vb2 + E9xoY/HOq4xC64W8lXo2VbGl5tu1EBv0+uNFNIMI6xTyKBtqkRaQHJcx4rha1e02 + ppsxncYpPY1B6IWjzA0AWFzb9bFvhXxJeBTug7vqHiWQNAo2Xti64IpR4/W5Odbm + 6aSerjae93g+nLpnUG0qEBDP3N60hUJOJqELzlKQi/T3LR7AMjZe8yYOEUFmq7fC + 7Sx1yq8rDSVWaS5gV6uiyVx3AZwhtphvLN5lPggJ08BsI253OmWBLRVyinN0fDZ3 + YHAwW36xVOyt/EJNcZ9I8phF/IWiZizjud3gpmSDQT6r8O2ad1hQlgS7Khp1TBl7 + 7vPJc+1sxZszMGHdPeMwNz41Nu9x0L7aC5xip0C8lyjHbOdacYZBDViOvxsPTztr + jJxIJhuRMVdY8dG2HuRjxqN+xc/mpMfy3ZlSmPmsUP3Ehn08jQ+7fVdvcsunRIZc + /Rlmv65+tdr9b5C0nVgynOTG6x0eV+G37yyfFsrNEpkHKLP1Bz0hmz338spleWc0 + mD7h/hwl74wf342Ha1/PycIXO7z1hkjNs25pWhOzbwt8tjF9f8nAzFtNcBQE0m1F + KMlWeGfjognU2f/RkkQiU6TSsZ/JdLe0l89M0CwX11Apf/I5pfOt85uLi39JT4+b + jcs51MT9h7Yo3WpklDc6skgJo646l9syL4+urZpR0l2WTH8VyjTChPN49cI5pLJs + WUjj6+lVgHC0C24Ic/MUQPASTQ9xkJGyrpOgeUYIoBw+XI5p4ZVVEd+Nq7OXnj/E + Jri0HR++mQXOeEuodib6pfTSaQkGMVGG2QZBRzdBDDRAErYN54aJq2oFKq1Ell8T + sVAAov6PqsEnN9gmTgS57+oByxSHuSTHdn7syVIqbS9DlrEwhz2/wTXK2FdJc9wV + m87neyw4CuJtvUyq6t32T0IsyPEaJrRi/w1Ycl3U4aDZc+yRBhSWkLrfE3JLNr/8 + hzQgb1TjKTuYNqRZ61DC1gz6u+t5LpuxbV/0gNv5H7fTaABGrUnMjx9BdRXBCJoE + hGs+X3adea7CAoGMayDUipjnQ0fZZNB+cUO6z3w/JUWeL1aO5jVTg5NrFLlm0v8u + mPEVGJdsji44H5+FBaZq4UOyxdgRrmX0lzwAuacPPdrPv/DEOprZS/oL44hMXbe2 + +oexdfEJXP+FsjfBa4maXTGq+vQkRllvHCxrrb7Cb3kDfjbr9s3WBQtkSh8ZnXo8 + jmNX/nUuEltMb+5x4ffMOmgaUUNFgHD8c7fiIi5noZqfCurZGDqu0sbpOcsNNv0d + Ws9Qdoh2c2K1CkuYYCLaR/Lt9DDZuxPs8CaJNGc2R8hiDbzrKrIgnn0rCGhV45l7 + 2B11+TCzdgCjTDKdFoCakvilCxtLYWCbh8HaBJ19w+zyYUaOGCXuEffofPiOtACo + 9rzkeAAAy9fJl/aYDDtggKT6gnzg02DeFfQZESowmA9ZNgjVT/Snko4pXjUuPbB1 + bdJnyB+b2RRxcJe0h6ocO98XZR5n9JAswETArnpJZN7b9Y5scRbNrLHT+uSrGtw+ + Q3vS+k26KRbO2kD9srA5QaGwtLAibgAqzfXokoLbDBSZouHTHcyK2WcggOpeBDYj + ufB1OPWqicc9NBjEiDHZBG0MNODJOLj3iS+zVF9knoYm6kXXHXwafV//rZIkveuT + 64NrR2ao/GrXrIvQnrkK1G5xDE70TuYg4VObadRO4QDljwR7y886Ew11s0Xmb1pm + orZUsfDv7oQuoNJT6981Jggq4zCTr6mG0ToJmV3bWQ1+ZTTTNyfwo9Q9DAlAJO20 + NFW3CJmBQN/kndhA4FnIPKu4tyUA1D47nmGEsd82mS4S1xe4v/TyeedUv3DRGDCJ + 0Uf0zn9iJNx7KgteZdrY6dA3m4EW7kGLZCWZM8+HS3gFBy5hb9s/REqoAy0pNYzs + ThYMjLW52tVMTAGxqlUIKbr/R8VJ6tG65/OSmys5+atxvNo/S368BMEHain3OvlT + ZFgYa6HyWpGvgXTsgThIyHKn9YpmIlfLPQ4rRMqVlzj1l5PTacUlPMiaA3bH2g1z + qajFrohvkS84n4zNWWUAhbD4mKJioHIt5CNE2Xj/pKNvGEXNCfv+/kFZI+7ayQlx + T95QKXbbawLk+4F8oBXodYE7g6pJ386vkGEZHcNv+5Hgh0oTZdCjZzh/iYp4dhS5 + JSLF7ZRuv4UlVLzdy7brLfnmpzGsaByy0VubTg0gwKm10b/axSyj3QGgumh6zoxR + cluzctSaWEPJjzXSOIrPzhX2uInrbj5zudoyDDzOGembhJEP5nfLUkJW29Hn2h2z + cPd0JBJUHOL0lIzrqpRwrjmYn9X2niQLfv3rLfvUOPw7ysKjPZbl2WYs6MwvDKxm + xzOqyGy089extzWXVpKQtWgKVv61X4yA6byt6xDCxRTVjozTsDRVo/Bfcg84YlvA + z5kwbzgAUldO0v7vMVff3Kg6ERqhtTv57APMeoG5FL7RLAvfOekoBrUiCwHvrqDv + K9unS0k24haWKgxJ6Fx6ZK7kIlQSQ6aJZfQCbLXAGO6uC+Kd6WDYoW1fIB/fLXpz + E6DbYs5+H5Fv9mSN9SQifonvMb9W3UFvBsmicNVTFvf6J0OIK+5UbuGsPJyYLGh8 + ecInwxoaA0747uh3AMP6fur8K/nv67Adsay8WKynTZNeqPRc8NANeep6UfWmttpo + tbcnQ5M4ThkamESkdbs+FuIGQs4jpGvMME0Jn0VF1lpWQgFVOnvbA4ew9YyIuIg9 + tViQaBKWRZymfEvwV9CCoD/gdBUuLCPxN5ZUR0OuJRakqjYZhLHgY/TiPeFAa5ju + GZpdBQCuwSXGGM24dglnye+QSPxLMOwpUDUsEzeD615CbWV+v7MfBJq4b53gk8De + dxUlf/IcJOuk + """, + """ + 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 + zFV87cgzdg== + """, + """ + 3AB784AB86F32D1D7A3639D5BFD514C825D23E4B + """, + "PLACEHOLDER", + new PbeParameters( + encryptionAlgorithm: PbeEncryptionAlgorithm.Aes192Cbc, + hashAlgorithm: HashAlgorithmName.SHA384, + iterationCount: 1 + )), + new(Id: 4, + SlhDsaAlgorithm.SlhDsaShake128f, + """ + 2D0941E8028BE96BEDEE1700355DA0E5BB74E5E1A34C165D45C900F5D35486AC124BF8FCF2B056B31BF78600767E48775144A96FDBFC2EF65EFDFCCEAEBB00EC + """, + """ + MFICAQAwCwYJYIZIAWUDBAMbBEAtCUHoAovpa+3uFwA1XaDlu3Tl4aNMFl1FyQD1 + 01SGrBJL+PzysFazG/eGAHZ+SHdRRKlv2/wu9l79/M6uuwDs + """, + """ + MDAwCwYJYIZIAWUDBAMbAyEAEkv4/PKwVrMb94YAdn5Id1FEqW/b/C72Xv38zq67 + AOw= + """, + """ + MIHCMF4GCSqGSIb3DQEFDTBRMDAGCSqGSIb3DQEFDDAjBBALlY8ikq+4LtRjJn3/ + uG/FAgEBMAwGCCqGSIb3DQILBQAwHQYJYIZIAWUDBAEqBBAz2S5pXftRWshroWli + 7pZPBGAHWQiaLeC2sZZ87EIJ7CPaNBnCp9fE6cFQEyiKFSczZKAeFoMenI3WZ7fi + oXr8WVXdhyZ5ZR++XDUjX+y2EJUNLfRdYGRqt3WY0ko8aWWeUhLMeoFmoXTRMhhD + qaAxaKM= + """, + """ + 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 + V1M8K2yvsbsLxSyCVrxyxjCuAllaqCx0hg== + """, + """ + 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 + ogx/Z92Gal1KsZo+uQQI8KzlpSHM5XI= + """, + """ + CCB830AE242B832951B14F1189CD290ACC4D01EC + """, + "PLACEHOLDER", + new PbeParameters( + encryptionAlgorithm: PbeEncryptionAlgorithm.Aes256Cbc, + hashAlgorithm: HashAlgorithmName.SHA512, + iterationCount: 1 + )), + new(Id: 5, + SlhDsaAlgorithm.SlhDsaSha2_192s, + """ + A9F3D18081691068B6FB2D3765BFA90FB0E047A166D032CB86F776AB27E784E0820F32897834685CF870BCA522FA21F21076616533EA7D25AEC56AB5BA2AC6133D32C81603CCE52139B4D12968DC3651CF95B3114BD78E6472B4437E59B2B285 + """, + """ + MHICAQAwCwYJYIZIAWUDBAMWBGCp89GAgWkQaLb7LTdlv6kPsOBHoWbQMsuG93ar + J+eE4IIPMol4NGhc+HC8pSL6IfIQdmFlM+p9Ja7FarW6KsYTPTLIFgPM5SE5tNEp + aNw2Uc+VsxFL145kcrRDflmysoU= + """, + """ + MEAwCwYJYIZIAWUDBAMWAzEAEHZhZTPqfSWuxWq1uirGEz0yyBYDzOUhObTRKWjc + NlHPlbMRS9eOZHK0Q35ZsrKF + """, + """ + MIHVMFAGCSqGSIb3DQEFDTBDMCIGCSqGSIb3DQEFDDAVBBBMbVxCnNl5gVEkXjiD + 0gbcAgEBMB0GCWCGSAFlAwQBAgQQfssmDcrC+zc1oJYbt1LqVwSBgH1rlrhuGQ18 + 4+82+VBBTbZYJL447fs5n4c0wU2GKiX7+s5r/ekdkR3G1p93h/SS3qdV6UYz+H7d + Y9DvYQlc0VU/aZiSnNjGevyuDP2F8Pn8c1ECQP22G1R/5Pl1pmYFK6/N/rY7hlkV + cf3VrrUanVF03MDOrfVuNMHYBy5ULr7N + """, + """ + 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 + BAgiBAwwZyKvpw== + """, + """ + 09D4938B35397A4B328518A22EB1BAF160F8411E + """, + "PLACEHOLDER", + new PbeParameters( + encryptionAlgorithm: PbeEncryptionAlgorithm.Aes128Cbc, + hashAlgorithm: HashAlgorithmName.SHA1, + iterationCount: 1 + )), + new(Id: 6, + SlhDsaAlgorithm.SlhDsaSha2_192f, + """ + AA5AE9DF3123663E421FFC7F51816E9D4D29165B15A8757E52C3938145278F6A947DB9C9A9246E64DC88E587ECB0F7F2866CBD0E333F7C6DB5840BDCBA300C07BFD70CC57461662A359838324DF414FD9E2C1CA96F0CC7E35130D5D44B52C923 + """, + """ + MHICAQAwCwYJYIZIAWUDBAMXBGCqWunfMSNmPkIf/H9RgW6dTSkWWxWodX5Sw5OB + RSePapR9ucmpJG5k3Ijlh+yw9/KGbL0OMz98bbWEC9y6MAwHv9cMxXRhZio1mDgy + TfQU/Z4sHKlvDMfjUTDV1EtSySM= + """, + """ + MEAwCwYJYIZIAWUDBAMXAzEAhmy9DjM/fG21hAvcujAMB7/XDMV0YWYqNZg4Mk30 + FP2eLBypbwzH41Ew1dRLUskj + """, + """ + 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 + BAhL6vTdUVe9+w== + """, + """ + 4F27874DB140CEBF3DF52F5C48A92FA45ECDF25E + """, + "PLACEHOLDER", + new PbeParameters( + encryptionAlgorithm: PbeEncryptionAlgorithm.Aes192Cbc, + hashAlgorithm: HashAlgorithmName.SHA256, + iterationCount: 1 + )), + new(Id: 7, + SlhDsaAlgorithm.SlhDsaShake192s, + """ + 86F07D0923AB7C2C4FD4B96305DD0525BBACF1B4A73F77E837E975616D5095E712875CD71081ACA8C4C4B735E591D78ED1C3A44E2BCC989613A8EA1AC203E3B8CD4B3BB580104A44005E2BC0B1F305F8A71CF972A080E3AA066236F2EFCBC9F1 + """, + """ + MHICAQAwCwYJYIZIAWUDBAMcBGCG8H0JI6t8LE/UuWMF3QUlu6zxtKc/d+g36XVh + bVCV5xKHXNcQgayoxMS3NeWR147Rw6ROK8yYlhOo6hrCA+O4zUs7tYAQSkQAXivA + sfMF+Kcc+XKggOOqBmI28u/LyfE= + """, + """ + MEAwCwYJYIZIAWUDBAMcAzEA0cOkTivMmJYTqOoawgPjuM1LO7WAEEpEAF4rwLHz + BfinHPlyoIDjqgZiNvLvy8nx + """, + """ + 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 + JnXV5Ic8wZjdhOcDr35bYwQIYU9qvBQaOmQ= + """, + """ + EDB6B1FF255A1515BD0C05CDF0A6EA56C460CB9A + """, + "PLACEHOLDER", + new PbeParameters( + encryptionAlgorithm: PbeEncryptionAlgorithm.Aes256Cbc, + hashAlgorithm: HashAlgorithmName.SHA384, + iterationCount: 1 + )), + new(Id: 8, + SlhDsaAlgorithm.SlhDsaShake192f, + """ + 6354AAB518C2AE05DF62139BFBAE67DB5F878DE3E947A2DC2BBEE38997F771B0DC124D1E6F995732035CF53BFF04382D068A6040F003719A0754F9121EB2F92C851586E10C02F2A2537FA31E2B1DA7703C557EF7BC964C872EC68C2BC85DE453 + """, + """ + MHICAQAwCwYJYIZIAWUDBAMdBGBjVKq1GMKuBd9iE5v7rmfbX4eN4+lHotwrvuOJ + l/dxsNwSTR5vmVcyA1z1O/8EOC0GimBA8ANxmgdU+RIesvkshRWG4QwC8qJTf6Me + Kx2ncDxVfve8lkyHLsaMK8hd5FM= + """, + """ + MEAwCwYJYIZIAWUDBAMdAzEABopgQPADcZoHVPkSHrL5LIUVhuEMAvKiU3+jHisd + p3A8VX73vJZMhy7GjCvIXeRT + """, + """ + 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 + cryVu5GkzRcZUrbefZk0zkgv36XFyJ9eRWf6Esqt/aVqyrD2BewkTrvm9XVrvV3V + sH8xijBXvHcX0kD79B6ayJfMcMSaboIQZgOzTcV8RfN3PslNrzra6tSoXxzAlH8B + XBlPdcKTbpDu8qDEBAdp+Rekr6bligv4Ih6RGmacSahdKicHN3AXZSxi2nQPMj8P + J01rNIvqfqmJVB9thIdkXkX6eWqwQuZ04XVUZqQ03xOdNVsU/MfkwbMwxRUlDM6c + 9j7qkkGFgLtBZmK7hhAoo+GCPrG12qSLjijpBKZ6mapOxnYZ/zvg9k3M1ectT5nI + lRWfEE6FttI4Kyedh4EyA7bbMXLheJAVTtRRISBcqm6priH5hkkVmyh/sD/skRIA + 4wr5NWrW0NEzRfnt9i/aXeYn35t9VNCU1Z/Iv/VL8Dn8k66rMXdsqYFRJJHpQzyR + RgYVbWGU5CO79YClSY78Lj8f3wY4tPR3orYlo+NTPEU87eWso9kvIg+hjDXwlXUX + qDFnNw2j82Cm4LpDM3e6M/gsFgok5+EIhuiXoubfVh4F68SHmDz8wIgMKOaC3sFJ + TLgQJnLyzYONcOA3INmm/hMdoIZDgsUBHQQjlO59I/VI6zjjBegX5V2idgfIx6Gz + 0jaeDWRn70XGUTGauKbvR1d7gADCcMWVRlP3awnkkXAaNtI9THu2yAQMJ4ydjjlA + 0MvPWBBouZ6yoy/ojbnKraGnTo5yTeq8oZ3bbdtz0VicXad+716LYKDZtq3gLc7L + DjIAVJICsiUNGhaXDsFePYcpkSq3TefZyuNzxp4XSaxw8fG0cwcSB9IsSbiH2nYP + aFNHKirxLBm3XW5UEmjOgm8c1bR3VVqoBjmCNB7Jmy/euSr70sa+0Il3iad0eVpz + vbkWNMmjNYZrLYly1nQkjSERPfblIX0FRZQhtqdTm0/0xZYoKbQyy5saPPHlJ7Wy + bM7xqQLbHRcgYrgtiGR7IROveJQAgsnKDUVbCkA1Xs+wfUAJzstOPrfNh5V3/wBs + 7QsFr5gtCmmztuv9Mpsjo6m9ESrKS4itoa5qfL6PXMq8TZGxwL7heh658PfihuL7 + NU8keKct5poJAC6tuaAzTUWeUd5o3aybG80ftKj+mbul5en7y9m2mUxnk86uaVlH + 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 + 4wGqX+nwsXOdiXycMbqueKJecpMRT3pkBwVTgrURxkud0KfPKUz9ssl7W/m28TFR + eChbL5uwY+L7GA9chlQtNHZdssMTjrAyvrAIJw4ytOjJT+7f5RaVLfFaNTSEadg4 + g8f6dhfdn0DEW/r6/jRA5MBnd3H0rKPqd3oi4UE96wpdG/+9eGIoWDOhhp5ILGbx + oecTEyitpFhXup7X01r4Y2sd/tZzHHsQod06+uJzyHOpK2E5l43RSTnvGWEsCJ76 + hrgGBqc1Q001rjscJUDWj1QjWam5swXv3hGI7nzSxQ951B3f3ZllBJ9dd+7TYR29 + jiaVa/oLno0QGqTq9+D5jcVOAlLIHn2qDtU+ktjjUyEZSdRQYGd149u2qXLEZuNu + 0IWjUATCUlaFOoCIAjppSyPQDrO5GWQY3MtnVo0uzZoWBPpDDT4UK1UDMyYA2FVt + Hc7zooB/0RZYQtGG8Y2bMuwK6Oss0Y2ZvScozxxe4V3174tQTDgcN5zTI0p9wyB6 + 3QkQiOd9vqwksQuQm5CNK1VDoG9oqtIAhqRaCVngeJMsWrfsc39da+jdroomOu10 + KrMfcKcT4jJMii+KJihtzdEDyp6vQKFPkAhbo4DZ50qbnIW1+PxMAUy5pav5+3sl + 7uBJf7KOPP8A5Bi87kefXO8C6+uN9AEkIha3RVLY4LXzD1wvpIiKVf3PXWIlSnIb + cWlW+2IMVU02KqK5bEVm6CZuHiro5a/AzLYw59l5EK6sNeTdy223Km9zF1iNvR/P + mt9tKfsfPx9lUlP6FxDmVo/YJ+jK3WLi1tOqr37uS3L/YwremU58N745cZvXE+4/ + AC2m1U6/KVuRtq2wndkNhYJmFFBGPHmL+Gv4yNCzKvDLbxf92vKHjyQEvqb8o0gn + k/9TTxH4Fz9ZYLKzqaIVCKa0Lb97duI9NVf6pB2D4HZIbMmORi+MVNzCp9Maysdj + t9asIHF3O+BPNdvC7MrP37GoXXLt+YH2a8f4zF2gs1d5W3myoiMmysLG3eovVULv + oFqYY7FX3cD1RB9RBRNItNfxqyRzsbTlYZSDB1ul0Qk1xDuWhdkzNhdYNk+qvVF1 + X7/ggykT8l7qO4FV23ussAH9GnImOx6wJmxd+hCo72RvBs4t/HRM/9lvaeamG7jm + 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 + Lv1rD7sdVis7ce6A7SNuYgQIK6AiXal8ZE8= + """, + """ + 989C0CFE50F25F76B0538BAD02554708EBF374DD + """, + "PLACEHOLDER", + new PbeParameters( + encryptionAlgorithm: PbeEncryptionAlgorithm.Aes128Cbc, + hashAlgorithm: HashAlgorithmName.SHA512, + iterationCount: 1 + )), + new(Id: 9, + SlhDsaAlgorithm.SlhDsaSha2_256s, + """ + D25258C8EF6D311A1A944305039BB42F02088A6CFF72622ABC7E6B1B058771C78665216EA67B8BE9AED88C888E3CC16A8B5FD10614240A5D6F5825215495DD844FD59C124E005446D37A1353DAF3017EFCF569278752A1E8E0796EFC2BB442B53C38011B262C60A8A95A5C0A10B40756AFDFE02684DBAB81A3735EBD3FCBF2C7 + """, + """ + MIGTAgEAMAsGCWCGSAFlAwQDGASBgNJSWMjvbTEaGpRDBQObtC8CCIps/3JiKrx+ + axsFh3HHhmUhbqZ7i+mu2IyIjjzBaotf0QYUJApdb1glIVSV3YRP1ZwSTgBURtN6 + E1Pa8wF+/PVpJ4dSoejgeW78K7RCtTw4ARsmLGCoqVpcChC0B1av3+AmhNurgaNz + Xr0/y/LH + """, + """ + MFAwCwYJYIZIAWUDBAMYA0EAT9WcEk4AVEbTehNT2vMBfvz1aSeHUqHo4Hlu/Cu0 + QrU8OAEbJixgqKlaXAoQtAdWr9/gJoTbq4Gjc169P8vyxw== + """, + """ + MIH1MFAGCSqGSIb3DQEFDTBDMCIGCSqGSIb3DQEFDDAVBBBsr4pb7CK9I0/uFASe + QDxxAgEBMB0GCWCGSAFlAwQBFgQQZ0KIerWO+p0IW78/Bs9Y8gSBoNbn0V49RL5K + 8dt420tw5shqxg+MqfNSd5KD3T5d3p4V+9WrCdARu6uK6sm8T7g91o2KCqNmP0h4 + N67rSzn4i5KTmAq0QHD/uBm9iGHxqgNzPklv11tFxRVCclOJ1Lb7jEkk6WmPrBQS + nM1BQFCOdnwsnqnlp17i4vHKGTFNUwOiyfwIy4iRCbb83OXUZU8lMInMXXaqH0se + NW1mk6tVuTM= + """, + """ + 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 + """, + """ + 9862CECF5A093E1842EAAC4D1E3B55DD50397549 + """, + "PLACEHOLDER", + new PbeParameters( + encryptionAlgorithm: PbeEncryptionAlgorithm.Aes192Cbc, + hashAlgorithm: HashAlgorithmName.SHA1, + iterationCount: 1 + )), + new(Id: 10, + SlhDsaAlgorithm.SlhDsaSha2_256f, + """ + 1A0D6B9D3E7D667F81D4F44963409F5CC4C99B04F56ACBF7E194371E42AC1A30CD988646A102EB2283A841F243A01E8004AD02CAD47E54A5FA48EF751571E5BD6A4C7DF1AF27128F6AC03984E8C54B80FE349708021E8864B4EDFFDA4887B5576842B282955F91EA87F7477B5266F951FC3617D1D914E850C32E0BE5DB1D97B5 + """, + """ + MIGTAgEAMAsGCWCGSAFlAwQDGQSBgBoNa50+fWZ/gdT0SWNAn1zEyZsE9WrL9+GU + Nx5CrBowzZiGRqEC6yKDqEHyQ6AegAStAsrUflSl+kjvdRVx5b1qTH3xrycSj2rA + OYToxUuA/jSXCAIeiGS07f/aSIe1V2hCsoKVX5Hqh/dHe1Jm+VH8NhfR2RToUMMu + C+XbHZe1 + """, + """ + MFAwCwYJYIZIAWUDBAMZA0EAakx98a8nEo9qwDmE6MVLgP40lwgCHohktO3/2kiH + tVdoQrKClV+R6of3R3tSZvlR/DYX0dkU6FDDLgvl2x2XtQ== + """, + """ + MIIBAzBeBgkqhkiG9w0BBQ0wUTAwBgkqhkiG9w0BBQwwIwQQljSXPxhWoluj7hBb + d+h/6QIBATAMBggqhkiG9w0CCQUAMB0GCWCGSAFlAwQBKgQQQOy4AlWrAojjPS/T + GKyKBgSBoB1636g676MeLkpD08Zn5euuloJvy2j760ZlsVGNxs/g4spjHaZ60kZb + jnG579f8i6+FkU86aIFz9wEtgnIUut+qlwRrG5B8wByYYjJWtGbm2V+4p5KCK0LY + ZcM43EXVEqtiHBHsVg+9W0yvSstTqTY2obzZZvMWYGhUeF0LcqPa8Gd3jhG0AEM3 + oiZ/6Ved+Bq+5Nz5McycXShkaQ9IRx0= + """, + """ + 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 + """, + "PLACEHOLDER", + new PbeParameters( + encryptionAlgorithm: PbeEncryptionAlgorithm.Aes256Cbc, + hashAlgorithm: HashAlgorithmName.SHA256, + iterationCount: 1 + )), + new(Id: 11, + SlhDsaAlgorithm.SlhDsaShake256s, + """ + B5E6EF16BCBE921E35E1167BBDF9F13E2D924D610376852712EE35D2E9FE37D60DE7C0C17EC43E1909870A7167472CDCD8A8A62A70D23E5782433006DFD2167310F86C5E1E925786168E489F39D79E60CFA21B77310D29A9301BB6B5B7F6068FCFDFAA052ACF753D25B7749915E034DA606F544FF6903BC8A37ADEEB1A1FDC76 + """, + """ + MIGTAgEAMAsGCWCGSAFlAwQDHgSBgLXm7xa8vpIeNeEWe7358T4tkk1hA3aFJxLu + NdLp/jfWDefAwX7EPhkJhwpxZ0cs3Niopipw0j5XgkMwBt/SFnMQ+GxeHpJXhhaO + SJ85155gz6IbdzENKakwG7a1t/YGj8/fqgUqz3U9Jbd0mRXgNNpgb1RP9pA7yKN6 + 3usaH9x2 + """, + """ + MFAwCwYJYIZIAWUDBAMeA0EAEPhsXh6SV4YWjkifOdeeYM+iG3cxDSmpMBu2tbf2 + Bo/P36oFKs91PSW3dJkV4DTaYG9UT/aQO8ijet7rGh/cdg== + """, + """ + MIIBAzBeBgkqhkiG9w0BBQ0wUTAwBgkqhkiG9w0BBQwwIwQQ6fqF2xigIqtaIULg + aEFXcQIBATAMBggqhkiG9w0CCgUAMB0GCWCGSAFlAwQBAgQQkvTypl/QpDP0PBvy + Z/0/IgSBoPvR3Cr0AvKK14xEsmkkvWiGkD3/hEFljJP9C9s3KjM2BDlcMHFRpFQn + /DwRmg84oIbpuCr4FnKeWau44aDeTiGumfPLAXf6NTEiKgsHsLXzj4IrZHkAcQK9 + VZixG1+AAp4MVp2ott7JfwUeKDLwD3JI+39rAHQ4crS2ZDHGcKZn8jJt6nU/tJJV + /FajToUYTQZ31nZmf6EEp0NmCURVujA= + """, + """ + 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 + ACwECNh9sniTJ5c4 + """, + """ + DEE1938AB123E25DB30C46D2A63BE0C2C84C9246 + """, + "PLACEHOLDER", + new PbeParameters( + encryptionAlgorithm: PbeEncryptionAlgorithm.Aes128Cbc, + hashAlgorithm: HashAlgorithmName.SHA384, + iterationCount: 1 + )), + new(Id: 12, + SlhDsaAlgorithm.SlhDsaShake256f, + """ + BF7065226752BB2232A0000DA5C9D6FD6EF00B036D454B09E2DD340CDCDA38279394EFEF4D77A82B1F476C7ED7A7ED2CD60A580E697B8BF4A91976115D40AE264E2A7604515AFB1FFF9F54D5331CDBBC57B9D00E545EED8C09A1D228395470997C2D183DF2D32294E0C7DC0464E95C2A8EE44D9322AA64DEBD3746E00958B60E + """, + """ + MIGTAgEAMAsGCWCGSAFlAwQDHwSBgL9wZSJnUrsiMqAADaXJ1v1u8AsDbUVLCeLd + NAzc2jgnk5Tv7013qCsfR2x+16ftLNYKWA5pe4v0qRl2EV1AriZOKnYEUVr7H/+f + VNUzHNu8V7nQDlRe7YwJodIoOVRwmXwtGD3y0yKU4MfcBGTpXCqO5E2TIqpk3r03 + RuAJWLYO + """, + """ + MFAwCwYJYIZIAWUDBAMfA0EATip2BFFa+x//n1TVMxzbvFe50A5UXu2MCaHSKDlU + cJl8LRg98tMilODH3ARk6VwqjuRNkyKqZN69N0bgCVi2Dg== + """, + """ + MIIBAzBeBgkqhkiG9w0BBQ0wUTAwBgkqhkiG9w0BBQwwIwQQVVNsujzsiE7eYcRR + 3LpGTgIBATAMBggqhkiG9w0CCwUAMB0GCWCGSAFlAwQBFgQQI+7nNpjsQUrI32PQ + ItRfkwSBoMgY8IBmBgfbiRXsmkfI70Ix4ZQNjyfh7yGW7JZGS7V1se/DL2NY4OCS + PP2uYflb//Vm6znVKJ/QUWcxTVqJNg6ywlD9+X4nxCk2zS5SD/1o4jZlOYBGUqrz + mu+zfwFdUs2L7OJ+LR0U2nxvwlgZbpeCJQd9F3S+btXan9ac8lP0DlDWbQoj+5z4 + ukmshk4NVuTIqD3XqyTmAHuaLXHMzV8= + """, + """ + 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 + NV8ECG/fIu03IoMU + """, + """ + 7E86D724DAE3E2DF09EBAB5D4FB57A7523C1DDE1 + """, + "PLACEHOLDER", + new PbeParameters( + encryptionAlgorithm: PbeEncryptionAlgorithm.Aes192Cbc, + hashAlgorithm: HashAlgorithmName.SHA512, + iterationCount: 1 + )), + ]; + } +} diff --git a/src/runtime/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaTestData.cs b/src/runtime/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaTestData.cs index 9289177364c..1eae4974258 100644 --- a/src/runtime/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaTestData.cs +++ b/src/runtime/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaTestData.cs @@ -8,7 +8,7 @@ namespace System.Security.Cryptography.SLHDsa.Tests { - public static class SlhDsaTestData + public static partial class SlhDsaTestData { public static IEnumerable AlgorithmsData => AlgorithmsRaw.Select(a => new[] { a }); @@ -46,6 +46,497 @@ public static class SlhDsaTestData "2B8109EC777CAA4E1F024CCFCF9497D9" + "9180509280F4256AF2B07AF80289B494").HexToByteArray(); + internal static byte[] IetfSlhDsaSha2_128sCertificateThumbprint => field ??= + "FC46CF9D0E6267836153D76708B5F1D11155A74A".HexToByteArray(); + + + internal static byte[] IetfSlhDsaSha2_128sCertificate => field ??= Convert.FromBase64String(@" + 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"); + + internal static byte[] IetfSlhDsaSha2_128sCertificatePfx => field ??= Convert.FromBase64String(@" + MIIikwIBAzCCIk0GCSqGSIb3DQEHAaCCIj4EgiI6MIIiNjCCIRkGCSqGSIb3DQEHBqCCIQowgiEG + AgEAMIIg/wYJKoZIhvcNAQcBMF4GCSqGSIb3DQEFDTBRMDAGCSqGSIb3DQEFDDAjBBA8ekXULsx7 + p87/yC/Sn5v9AgEBMAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBDZA8q6IUBZ09jX3R3ZyPM7 + gIIgkIRa+6roH4nUtZdOjbJmG1Mkl564uZh9poEf9wiNUKbeuv54ZNf2GVC89DnMMiq/HB+J92XZ + 663bLfjjxG6W9+Q2vLKkfoPEBrPXkoSIGLxOnd+i4kNrW9clyTYXAb5GMmQyJFHz7Gaka7XSrnfw + K0qAbtSp/Fl4XEeLyJuPAs1vzpmb/G1UzfMfFDGcmY0VpvszBhNbkR/LGc9v47RFvPdvdRhBy/g5 + Zay4lSlUj5MFLXKpwQ+LDUWVf8o9f6VzIail1+L38VQsjh8rN/fO1uR245C1u2E2igrBZ/YYJreQ + EnqwCQrsU5VHcSsLFhfhR2JdeJp02iSpf8IoomnFDQa88CrCEfyDL0p6jsm6GARmpXMsQlKbK14v + XPV4U/Sp62xbtNQEBq+tx/jiE8sPIP9+SWC+H/rqV+Zk9lClhFoygDhDtorA2WU2oDKno9vN+kJs + x8aBXdv+WPa9azoWRwnD0/QU0c9xihubeFaq0MfJbDi2tlHucZaKh3FkygIrhflN3u9y7Rj0KIb4 + SOHbgVJj89IGKqowGHam5ckMgYGaqcqr0Pi/BH8dT3FQWJ19ZraiSegLB3q9r5VhDPShHEF0iscu + c/u5CuRXd6vEvfJFpLLL3eR6AkhxK2dKsKqnerJeRTwT5pi2VwwY8AghDY95OjFMC8BYQgc5cM0X + jkdzA5z085XfjQB0Tgioyso1jtnDHA1rTd9firypTYPX3DrAH4AElHog0FuNiIUloDJZK0RL2llu + K8bMKFnlrPDSL8PSlhX1+o/1jmchxWufy6237n2hHV79kauFebX5O6KWmPl/IOHLougY7MtXKfaL + ZGdo0rQgrLv4Xt7kNus+4p+cGp2FuubpXPvpeGJtBhVNbe5UyqZNWseQ5pXPgqeT86V42fST614s + MZ3kpC1VtBOiLzO8KCxCMME1mElHm9hFA/Omm+1S/qH/hJGEy2KoexPgACa6VPXdAH4PAtTKD7a0 + vYPuL1WkJYjlkBnuI7+0kYX1N9fclupgIff/8dh+MNDoo2t1HxkEhpySEEtBzD7pCLYEoyGsa5RN + Lu1V/MiER/1k34s0jyoBL+cU364aTc8q7VXEdjyWCG+0L8sS9BhX4Hl7fUTyEu9eEm++0weDyH+g + Za3oH2yjzz3NmAVx54JnBG2JNLdImYJPBGz3F4fEuut+rf0+vcompMsmjR5tgjjEh0EiwSxL1HqL + FY7ACz6P8kZxXqj0P20yGeeF9wl1YbKfRxjza+7BVBiOpPdXuI4BvKp/ONRWXs32UGd5i5mbFylO + FVJv5+CxqSMwsmlcwzmsvU5pQRg1q4JffZv42PCCLvMdIAovbat7tlhHr39pefaYuDg7zg9jbN6z + yV6N0+e8hbMEbiOiu14oKayJJOyTEmXr24HNC/GsU00QLCu0T96XgN7VS9AJhlZTGeC/OEIErIEJ + AIWvWal6MXwBH6+2r/h59T49dqF8nZuK/tpYs5/hlvE+9Tu02GYFbOYWb2hMbtCZerVIT6LMr702 + SdMnbZFwhGvUFaliQSoGeGAZSGONsEq+XcOK9gsOai/PrBSBaxRwy63nTGYDdWkGbJmZ1WXJpETG + XD89X30HXqzWO1eiWVv9IjpVBSorUcB1dv3oSUTgGZV/XHv25R+9Swm+oySYrohiSWkJq2OwsQmE + mKWOT39I3zdAZg13x9muOEPf4NTC35TEk/5meuTyliX+/psW1FyQBm9Bvw3YpN2ivCw7vrnofkk0 + 4HrcTokev7B3EMDBJC/TNofGLeEglLTv97Aue3qvIyM/0D/mShIkOtJfCNaR9zfWmlRsAHDUQ8BB + ri/xnaTj5cKRxkhX44bAe6iaA5PrNLDylOlUzQiObP607pfO17AWiFf99NTk+PMmqZbWW+q6tOaR + TcPoh2EnxXB3IXMToNlzBw1NDlLoGM1muj9m1aYDmBlDQiKysrBnL5y40wdSkggMA8sGQJ2K0sAn + 2R0iah2AqeZr83CSoE/4EAkhD3eBs7aQLxCCigv18mWzYJSzwk9cAHyM1w7AN8giUHN5tYvsrmhR + D7vdAYASSbhC0NPyVlgi2h4yeizJHBiNc7aFYvFx0OpELK5uPoXWf2Y9LNBhFhPeyo27uwrIP4tL + h1tR8jYvZmjeYBoL7SnXiwa2kjxnjednKOiZ4lmcrkN5RW0DUCKJ9EP2b3+We5gPNjOdHH2l6ARj + rFjCdVgh1xX+tymH1t6Fnpemd6AhKKJTJoopyTqdOlzi6ptXOA7Fw/UvluQ8hPYZSJNveEWOJcLt + eyIRCkDxPCv7jcxDQbLV+P11zTCaEmtmQ20Nbyp4cHJlzffp4VOeAorhyclzaxmHxSEFc+bQFMh8 + ekpZD4l1CmdsQ5S847Z1Pq8TmZxOB9Y8Eai38D4K67X9EorzQQQqw3B6pjtbGvIbe1dfwkEkPmGT + +Dm1P3u4yzq6cqZYQl8LIfe9Xz9yWctn1LdjPNdbYuH3JidU5zX3Q42FTXOA5hCLKAn0rtTZVP4/ + eonC23pU3kgoA/Ywyy75zTRHhUoEGtQfP64BOEsf13sDrKWBBKm4Nu5AfPPPQ7b8wAz4RKMM2qRZ + U8Z1m6H9NTbseLwFztUkivgy7GQWvztqbYvQ6XJDxVLrfagR/LcFzQUdV2y7X4hqsp9CDnmwXJvf + Ir/HH0khIQH7PcpjvKx+m/HGNQ4d/R1aN58jGQI1Frhjn4TSd7as/6eI0XZUbqhSohIcHLtoLoNa + fmf8imvgA09vVHYhwB/vHm3EP9CX5HzaDuoGfvW8d8N3QwQzg30duIsGN1H56X3PrGjVD2c7X1F4 + J/Ntlo85LZshSXacQ3B/A6WbaH4zX0ejDrLnnIBJ51Z1YbuY9g/gjmRn9ZGMFVBrHTr4ZOGZRi1P + b1RT6ca0HbFn6hUDysVhcfN4E1N7Tcxhc/pVaejBVipHOHnWsxoIJrltSylDrUBFMYCaoJc8PT7h + 3dYmVDvMgxX96rkBnkrv/wc+104zxwjsTbWi+z5DOtgxPZoeAki3gYkNWEANjW4A8LsHWIBOzsFh + F5fDMFdxsl2/QE+v7sNfRB5gau87Bvv71KG/dFredJJ7TFHBw3XQUAnu908p7UMyHefe4TLDZrUq + 1M0JoB10i7/ymz+b8OB0b022KWQh8HMLxY4adovnJJBwhdbRd0taB44TaZyuAX2pAke908mtTHvi + 5Jqg9PiPpO9CwqcmJyKWyqALU7BMlWDmdv8Cbvvr9LqlpJm12dPnRlGT0GSByr6IAJDct0Hi4bhW + lw4lQBxaSrY1xu3R+qHbJwvDRVWP1luvDZI+b3ROdjZZrRquH4faxh/GzQDliHq5DpWaLhpIFDUx + 3Em1JimaXV9c6x9b60hdwB929C26ikE+bn6IriQEw+pneNl5dNj6MqOmVj++m9N6vlc/0fJTfzyo + 3GL75iEsiJ0zHfJQejZoIIzMmlJ5dp5N2XCvvrnIBVieC0PUhh5JpQEue3G7MWFFzKw9dx0hbfdo + 7uFnJQJnkhyAQggUOhDimtEiMEc2eQBG9O86YG5YpKn7M1SimBPV4HK/4sNuxyxwR+ZXiBhCCfOi + jUVcJLGiELucGy7Xi8jSAjCX/2EIB05b8yHtjemaTSTcNX4cLVi90J/Djud5LhodY0ZH4++l6saz + l7kwkp/oHiSOr3l7jmLuKFguLLfoq1gF+MmQaib5wfiZlG7YKblYbmb2hx7RAh282zr3MYqN58uc + EIH+EtYA1CCwpW5ttOLgtkJlLU98E/+mFtKsG5ea0dv97wxYKceS2MydgOI+xk1r7EyN+aqfbWPz + BSoV0Z81pYIQw3Qla/aFJjHrYaXmfpVM43Ot8ONVL7oXwqeUUBKnun8z3P9kK7+NXhMjZRNTIkSO + yDoJ0OO/kIjJlmUcvCiLPIVY07GJh7uhecs4ccAqNmbPRR1+R63ADufynlkPABGWuR8QMFq1tq+O + lmWFv8jX4nrDK5Rw6U+3mFm4VaOFlf598WKkWUjnlfrP/oVCsP2HXnuRCvtXHxujVUf8npsfe7tb + MvNa6KfLq88Tt9jDUdyWq55p1lsywBoxAsvMKjiuXIhYnja0d7LVaeuTa2I1gQgHrr1reitFmejB + DAAdVPm8XpoBYbRHs6hICWow7TVi7qDeZY5YzyL87ocq6O4nLsT6k5jCROH8WvWqz71ARYC+mWTo + MCqP8ETZgJgPm4jjcnb7lAat2c0Ym1DedwXGDIYSErGkGN9l1xiF+G6GYS4gxLN4WW5Osyg4uLo0 + QdgA0zgIURSmbsqOfI981Asc06zpXNqcW6a2puQf9JwA+bU5kZohBTGOeqM2dpXKVYuGk+Bn18Tx + BhM3gJ7u7ppAuvwuvfV9NXDc/C/FOBX9CZBpR1Mlc4gLK1FistGjPy4wnBaSsMXixD9KnOnQ8FnW + JMmqZo21OC8hoORY7jhZaXRK2Raz6y/m64IG/mq4/KOWmFBPfoVf/GkorTHSHZi/adrMyoCZSH9N + obcLF1KYjcZtEKuSkAJ0ujLBflv5lYuTXV9TFoMP8/cTJJyXwqnhsZTEanEZ3AYg6WIVKbA7VTrB + gemFQDZ89vwJVbpWJ5MzktSKNozF/5WLLgHIyeOlcBooUiSPoO2gIjepvQsfCSXs7iKZopImsPpO + XxVkx0q+wibWPtEdljgogeq8byaZ9mUUpZ+vXnajaX1Co4ogwd+EVkgUHhuomU72fAtZOC+oviOY + z3L+wqPHx+S0LYihTNLCrXsIcpBEBvi1EYioW86wKMJ6d6M+N1/Zl9/+nALpmurV2L7jG57biQCz + 8yEY5PFyFe3Mgf7oLS/AEcX78KFMhBov3qcUQRHVKfyqntl4kuiHsgtyPGJW+OKm6+234qQbr0tN + Xfgz+Qh+w8/DVHyQgHlGOoZAVJYe4FrEBXDjvMF095qfPmpBG+M9xxNLayXwnkWZyxDzDLe+LNqp + 6k34rztNywiLJNbp9OLYicBxuvpRKTShlGiLICrp+3i8vgQoKAJVbi6Vp7LQrya2nldOa8wGzp/u + Gd59PPSR28wNjP1p13X64g9JscBIQJxhLYJEnCQIA/G69ixBRqaUYAPvyk3HF9ORuyRATgP2CV2A + kd9irtG6sNxDP1MmHc0scTtZ0tMvULegmCb8vpbHfWpIPbO0SGbKxs+L/74wB0jCV7DbxEfpZrcf + ursgDBLUXqzV1yi2dNPv4kLq9SXIzwyNJzpm2nDnDaNIL9QnIxkqQBNfRGVGQ4g2jBdoHmZuBmR2 + Tf0Hq+7lhmVtWX3YxfueGQICUFysvb9ddmX49aLPoegI8gZxiyuJZujNR3tjDtncLGg0KSHOJWxi + vHS5hjmcGjg+iBY+qIVHiyEdcb2UsOJ3GgN2mkCOSAlXjYCwPyv5EauC8diCIHc8dI7TYrFcpl7i + tzcYuUAWB7feI6DfuhW1arBIpm3FktefVgJaiiKHF9qS7JVaXOConfyh6BctO/nfZlefIxi1xeJ2 + lu2f/+1h/XLiA2FA9DI1Z92tnkghjGYd38VOtqSJeOomPCRY5d47s3oUnlVwiJR/ZRc+QSAV5fYx + A3Hy3ukwpFKBNFRpe0tGkjeo6teVZkjkqf7NM+UyLJcdVdjn0rziG4icbApXjbP5DKCEdpV1oUhd + 0xUsazFbnf+ZgP+3O3/5sak3rkmw+91kGN4LkYAmfwfx91Zm1QAflSJqbzbqjNV6kL03ug24fDqG + VwkUTGJ1U8OgEy/uBVrvP1dXej52BgMwHOidHIn89Xx4IZho86XUkfpto9mU3OjUeWKF5niRGF00 + 2gx+xOfKiRXbyIMSf1E4SaSmX0U2MJpDAelPm4Z++s8VnHMXh2WtKtthX/82Bgk7WsEKGtmpMhlU + HfYyPwyj9lkFIGvFQk8G+bRVjEM22h0rzHpjME0XQglyyho2r7X4hAV4GBh1qH1nq7D5c2OOj146 + 1NWozNZT2XUNEzEvQmOM2sZurm/neQVow0hij2S85tTpYhWK/b9JAeMny9BbRc7BGkdjIlxT5ffh + wHur9oP4nueMlTGdnaUB+xiQHg3o9NuyoRWmBMUC8sY7DhrBGysgnwHnJDaLPsdNT087RA7POyTS + jEJ7liYZS+MRn3EspMJXsM5qN8n2ILaqRNP/5hHwXu+J9saBQ2SiCjFv5/MIkvwuk1Lpp82uaHYq + dEbVte+5hDHl6c/dd8R8tUwu64XTBfu7rj75doXvbHezJHA66OScJPqoqxAul89Oc8LnfldVTz02 + Uiv7uDjYZ1TUartJc0DS1AeF1omLDyQ9YyPe0/u6I2yMJ3GA0MnUREEznTz1nBUFacFgsvbcTown + 1QOtAYRo9tecOTYCAlTkimn9oqwujOuVqooRloQMs2d76SRrU+QoYrZSoBooPZOcLWZjNA2jKQ6l + +zXiF48tyq3QDynSSy+bnY8quwczMPskuQLEjC2PDA4NDWx9dJ9VmhjrTsX4MYIphv9W/RMuxpxW + ORTKz5ceP2neyB4v235a4Zqqt7eAuljRwoliPbbcGMoRAZ8Luji91shg945GLnmKoYBcdBJxx1pr + No1jH0RbLbrOHvxVdnb9ryufrWfCETPMANVFQxvjFXy+LkFR2iyoSsZwdktMaw2gweeUFxOk7DCD + lXZ2YaMX+bQl07pIvmJcuCD4JLd98pl6iq8QMx7dimDAB2R79Ptti5B9lPEJ5cfcqkqgS32X/7B3 + 455u2XmN6rTrEVLkXvo/cQcf35uiQa3vlHDZrRfH+wNUY+jI25iR7VVmDE76dNmojeCRoAN+sHqB + yodyIbDDuNS3q9l4byFszUmv+dowDIoPMvvMRQ2aikMJplMRPozsVLjDTnZPi4WS0p8AmixiBJ4w + DvevLSe0ZKwmUFnINTJ4uOW+3oy8+0wkjQo3FfGRsAoGbnamqXpKTtXTHp5ZTkoAYLebJ0ZeRMmd + GQqBvR5g4IPMJiHaTxdTu+11oYkJM9ezwfizY+W/quUYnTux/JmJ1/z0vtMvAbOU+tbAdcWz3028 + MCC5K2jGFEdp5tHHrHzBXp/NYAmD8o4vCT4Bn1rkbhXAVwHqOssVZ4qXaZbHniRHEyII2IuVAXa+ + sMo5z96pybDy2NwrFvSeBExwnlFSMu/CYEkNNwkIP9OoqPgmShhTt+Jph4BS1sRt1g2zLfIfffrg + BmdVWAXmJvBwmJElHprMNF0fCDr3LQrcfosB0w/jsI7C5m0Qa0nJM7ym9DCS5tJ/IPXcz8vDIKWs + x/iR5jkN/CroWeEEIoFVdIhAifF6Y/SM2TZ+XR3Eb3ONm18kwXFEwg0MTj4kzrsy7UHtdNXrhTSV + GcwPNEP/zkm1KkuAvFNyOvccWj95ij+vXNY2xv+NcpVITiljKtRRx1GPTrBgLPZz7sS1nubIQO/n + 3m8uxmyAzyq9amjaRGgM9J1V+G3PoZ5N9XYXieegCxbNTrNkw9b2NPEWjr/ld4Wak1Sk0B+1YKoC + c5pD6HLCjHDFcxNfGoT3kRXlv6DCRye8P/SwxygiZMs7J+fpMW8RmoGwCKO9ZxXYWvG7EHHyBpYQ + CGGbw5umtOdUtnEAp8LgNcZkPYXfdLGb5ffMm9HND3O2EypE4EcukhyWR0xXkIW68imoTg6F5Cs6 + o7ej1kSK7YLe4OFT3YObBt1/3ZtHXQcBhZBGz/y/mKwgHKPNUFwfqo5sSJ6navIWdTiXOKXKbOEn + dAX+bX+z8ZMkwjFB0uAnU1irmOsfHSfZgzNC6psIrBF5wgHrZ8Q6JaV8/sIWCFa6l+aXiMWWqZHG + 0VINDhjUIi2oGXBYaNhSnxDRq4SDGg2QiWxjEGEjxmkMVfk5QL7xbTslnUIqkBwdvMVrK4kf+o9e + EP2c+gFGLUJTYyqJhR/gFiqyN/dLjzUzAY9zSGQRVmzimUqQtW4ZyR4zOZObgU30R0R8gwQUKaw0 + 8GiC9oZnntu/kz/Cmj5jlOTzC6n0VPX1robDSb+0crH8Ax9eNloY433KdtkPz1JD1LSocelAwQ6o + jH0iNO9NxfKicDsUuEHOutvMiPiwzzrtLLoznWLItUyhOxW2rzdRj+A+p/EBJYaafIlGJn5NPoHw + jRpg4PziWIO6GCVCcXaYDJfRKOhwmoZ2kXRMioy0zftXQps/5eq92nfg+TcBoUm7WeZunxOoqEN4 + QDKDxY4kSj0IpOQN64ovGn/g1qC5hNOTSJzA9R2dMsjn9Eltg1BaFXpnr/wJbYqbNjOBKbzZsUps + ndvpKsiUY6bcjakcdgKL5dxo7DOy2+mAIL/kQqft1O/t5DluJ236uJlzkbSHzZI25bfhKvP1lWQD + ta4K2K79sh/GnbnFW08LFd4yXWR6T+Dh1gOhFFPWnqy5FV1+2aNvIyVhlG05S+wXGogf1zGa0egk + Jel/jJLe9x8IqPhJ9AfOawfx6H5oLVt9keDwpKkHq6JRrPIyJQFsgdXkzAkTeTTzneMTpJOYnw41 + HkWBZkbLLLNoLKJiCpyf7S4e7zE8wxhWni3ApqeTGMtCISbjLw4GCUhYpk8vFjIm7j+XYpXkXvki + Ou83iPDgVQy9XsXci+iiUA3IxhXaZbxHsXaFfxcokIK8tMoxnzdX1xteqkzPFK0fYggy/mG22S/O + jdXawrlsGZB9ZlzC3nAQ7miyg6hC9nPjExy+Y7LeWdGUF0Ja5MpLzxBZLu97CsYPoi94Yt9Wmjpe + 4tms3SpVVhrI9JaP6wsz1+v21PSSOpS9K8n/yIQwz2sYdk/9mMtQkjrmLomXWMpA3l62V1y6f2RG + iIedWwz43cdupIGAr5+XaRXf4R7mBfFWcubatWRNeSlxUEiZt1TuujtjHfu4CewhODke5r4lwvwt + BWj2jfMtc6wnrnEXP2D0EoMQO1K/H4rHmHVKZYWYPrQ8snmdsWFrV4IOcld68g3F2em8q5sKmN4G + fLMd2aLIOhuF+dKXKYaGJMP/eN5urH9CbYJtBNTWDSSZDpkMj8gUoQ6SA2+u5m29yD7bVzG3DLey + n2m6VOIqx208CWfq+KXqOFqCqn3EyiCLD9HSRp6t/FIFPWprWQoh35yl+GAr9Hh4ZzYI+MERlsY4 + A8U7mQjphcsdJbdyFLhfT/Tl1GxcuanRLhFN70YqXP8IQrgQwghXJd3tUAAuX4u8ZRSZ5Sfqju3u + /EfZ3VkQlS8yarqKYtD3ihoF7G7oNS5zIgFVfgvY3MvzR85rZclcx3pfTjwdPD9+OzRPw2Moclh5 + LNGb1kRyBZFXeD7lCTJYnq/RxZQofXmuOXhrSzf5RFYdjnfw45D81H12ILQq7mjnDUn5O6IOe+jq + u8u3ZlSjC60CqWI6iLkjkUC7RF13fKE+/u5sT3EB7kQ+Av256DEA33Ovd2n7hSM48Ne5yKuwnO4s + 7104FxfNqD8nW+7aB/NEeoGMowbIXRVNFqIgY2Xw4CSEIQ8pTvNQt+J5/Sv4Jic/waSo67InPH5q + u5jR10hXsqpaupfj/ON9x4cCDWdfTEjx0JeXp+niyLq+0pThdU5WsfHMdwSnlZWXDnztauJCIg7T + v1brlgqnq12bcTn/ugmWv4TJwE7F1HLmV1MZNQrf5ab3HfIgY1Zh9aoMZehEohkcFq0Xh4wheGel + LeoAai1vjXyivbLOsFM1Spj+wYAPp5sPfVMKFouDHVrUSIk5gOClzoZEtAZENQiqaFuNlRO/j57x + e1eRocU+P3fj52daaFfSij2CcoT6Kbl8ZYaR/XNcAjpmH8kqFgzUQNUuAx2ZJydGwTEl312Tnz1Q + 4e7jZTmAsKfSyPF6fer9bmBLTGmA/eXnOUf+5tb5JsS6fm/tV8I3eJWKSnK1iyvO6J/PhZPJ7axl + WcVz5qxBEufySM0pNDRXUJMulBNzgSJodtL62tura538rz6+WeDuJs2HL7xwKEPZa3j9NDyzVmz3 + 6ZFVxSIST6TGJ6zTVkKx1T3swdlca1eQui+e5g2vM3ifk2eauP+Uacquiz4zM8zcBRts5GzERW9v + UjC+i+N9jrhgDd3plv3hrPUj0w7ww1SRRhfOudBbdgKdrg103JkbulD3FFpKqWPqf6wStw8X/cCn + +DLowAscsHCZ6UnxixgY0z6Tin+FOrb5YU92kNmScHBKAkYOvZ4IZuVzbyiM3Tpi0ZvtohzOuw8J + Smwlo39aoIAH2qhZUhJjmX6Hf0NBiC5NNB7eYP87oFEmyVzdRkcfACQWiMTAdKYJ1k2Iqk7ya6+t + wjpOxi0/tordH72PoMLuldYy6O0SgQe4pfV5M6godg7ceeCve8abKgofs63iFEMmSnjeyTcb0cwQ + 510nZSLH4J8zndpbXyQ9RVNfUEFeVAttR9oguIG9rYJOijx2D7bdCcQFlTIfh6NKGb9pXgPXwWIo + IFbS/B2Oxd7AKJy4ZHuUGyaqkno6W+VdV6WIzWGtobF/YMvLO22ZSJ1IQ59XY3MQY1JuTbhdQ1Zc + boo9S+4aMnRWNJBUw+rsj0pYdHoQSoKIbwJxO9GvBFdVwa2Fv3ZC5pUUHljWqzEC/BEHXr8Mu+s8 + JdtvHQI9b3JLZSx2oTz0LMjI6Xwf7qasZdfdVndW4Dt+NFndExqoAUznCWjiJhtG5LPyZE42tMkt + Ojx00mfsMKYO9H0BPYd65qiN61bH20vPSeTN5Zm4X6KCQfKo96U3cWMORevzEq0p7HpqM7FtEZSN + 4z41qov2w7prhHT2b0+ZE3XFg1ZMhxogDWcy54K0daHArofnIA+cg/1ybDxvAVU0fztnlCE/8WZK + YaNq2INTyLZQCDjNuoC7NkFhjgwjL0zlvqppSKkV3pq+7LhN1nt/NRqe3VKrf7vb0rYfZ5MlKkO7 + 1yiSoJkI/ha9mfksMfSzihR0FaeZY81Y+5YuNUPFkodq2kVduWQkepdJHKs7I/EB2IDa4EgDGspn + pZReTRQ4WPN/IZnVne51CqXq190DzHo1osTgy3/9Qvri6y5Ws/AWCF+a9r4iNlXpsXUlGJeScUQs + W4rR+akCIXRtM11TDPpHtmRekZqMx19U8uJN8foPngP1HP6Fq+pEdFSuaiZ37n302WBvQx4G5k+U + k0Z9u2aAFjozH6fjjR/OiGSyUUHhkdS4arplzFTSQDwq17Qd+rF6OmzrP2mSfomJXrkgNtmP+tEe + SRj7YmLKz2ks5yePE+e0w1RoMIIBFQYJKoZIhvcNAQcBoIIBBgSCAQIwgf8wgfwGCyqGSIb3DQEM + CgECoIHFMIHCMF4GCSqGSIb3DQEFDTBRMDAGCSqGSIb3DQEFDDAjBBD7lI42Fm9bHNoigbxhIIG0 + AgEBMAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBAu1ZBjj+ap1lkxn4b1DS8sBGDKTC92vL81 + re9MdrwDf/Z7M8wP+/l8XK+EBOMfQMoPuIVlEXFghYtEdB69CR7e2/Bx7xD6Gl9BwUsz4w57ze3Q + 4mTys8sAHtJkQGUhDPE1YTw00J7oqAfMhdzPleL6HdUxJTAjBgkqhkiG9w0BCRUxFgQU/EbPnQ5i + Z4NhU9dnCLXx0RFVp0owPTAxMA0GCWCGSAFlAwQCAQUABCAubP2HPfJaPbDchgSrpgDZceKwhPu+ + 9j+ysQ+T65ZlCwQIacD7cnRNodA="); + + internal static byte[] IetfSlhDsaSha2_128sCertificatePfx_Pbes1 => field ??= Convert.FromBase64String(@" + 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"); + // Generated using openssl CLI. // // Generate private key pem: @@ -69,6 +560,9 @@ public record SlhDsaGeneratedKeyInfo( string Pkcs8PrivateKeyBase64, string Pkcs8PublicKeyBase64, string Pkcs8EncryptedPrivateKeyBase64, + string CertificateBase64, + string SelfSignedCertificatePfxBase64, + string ThumbprintHex, string EncryptionPassword, PbeParameters EncryptionParameters) { @@ -78,9 +572,12 @@ public record SlhDsaGeneratedKeyInfo( public byte[] Pkcs8PublicKey => Convert.FromBase64String(Pkcs8PublicKeyBase64); public byte[] Pkcs8EncryptedPrivateKey => Convert.FromBase64String(Pkcs8EncryptedPrivateKeyBase64); public byte[] EncryptionPasswordBytes => Encoding.UTF8.GetBytes(EncryptionPassword); // Assuming UTF-8 encoding + public byte[] Certificate => Convert.FromBase64String(CertificateBase64); + public byte[] SelfSignedCertificatePfx => Convert.FromBase64String(SelfSignedCertificatePfxBase64); public string EncryptedPem => PemEncoding.WriteString("ENCRYPTED PRIVATE KEY", Pkcs8EncryptedPrivateKey); public string PrivateKeyPem => PemEncoding.WriteString("PRIVATE KEY", Pkcs8PrivateKey); public string PublicKeyPem => PemEncoding.WriteString("PUBLIC KEY", Pkcs8PublicKey); + public byte[] Thumbprint => ThumbprintHex.HexToByteArray(); public override string ToString() => $"{nameof(SlhDsaGeneratedKeyInfo)} {{ {nameof(Id)} = {Id}, {nameof(Algorithm)} = \"{Algorithm.Name}\" }}"; @@ -90,337 +587,8 @@ public override string ToString() => from info in GeneratedKeyInfosRaw select new object[] { info }; - public static IEnumerable GeneratedKeyInfosRaw = - [ - new(Id: 1, - SlhDsaAlgorithm.SlhDsaSha2_128s, - """ - C64C3070CC96DDADCCCA1E504F8CD97BC67ECD3979643DC0447B43172D7CAF2087258E339C7936F81AFBF032A5257C06645AB97C14DB5F99D4E5D050F6703EFE - """, - """ - MFICAQAwCwYJYIZIAWUDBAMUBEDGTDBwzJbdrczKHlBPjNl7xn7NOXlkPcBEe0MX - LXyvIIcljjOceTb4GvvwMqUlfAZkWrl8FNtfmdTl0FD2cD7+ - """, - """ - MDAwCwYJYIZIAWUDBAMUAyEAhyWOM5x5Nvga+/AypSV8BmRauXwU21+Z1OXQUPZw - Pv4= - """, - """ - MIGjMEcGCSqGSIb3DQEFDTA6MCIGCSqGSIb3DQEFDDAVBBBILTCk3nTaPbXS29t3 - lszkAgEBMBQGCCqGSIb3DQMHBAgVykejrcsiMwRYqwZCq92KwbAT0sQxfgFYsvdg - 2WBMpFRvVeM9tDvtWuqBzn8PzMz19ZlP81dC4nTa1RKBu+ZFikjw6RsM99HbuCHJ - ZUVWPvbGgyzkKc5Gem2UVhiMG0UTdA== - """, - "PLACEHOLDER", - new PbeParameters( - encryptionAlgorithm: PbeEncryptionAlgorithm.TripleDes3KeyPkcs12, - hashAlgorithm: HashAlgorithmName.SHA1, - iterationCount: 1 - )), - new(Id: 2, - SlhDsaAlgorithm.SlhDsaSha2_128f, - """ - C2527316C8EA6BEF1A82EA808231BA1EE9F3282871C9E8FE319C02F72F88777DEBD1637B26EB3ED73CAA775E532D2C7C03EB07C873A171E01AA5E3077E030AC2 - """, - """ - MFICAQAwCwYJYIZIAWUDBAMVBEDCUnMWyOpr7xqC6oCCMboe6fMoKHHJ6P4xnAL3 - L4h3fevRY3sm6z7XPKp3XlMtLHwD6wfIc6Fx4Bql4wd+AwrC - """, - """ - MDAwCwYJYIZIAWUDBAMVAyEA69FjeybrPtc8qndeUy0sfAPrB8hzoXHgGqXjB34D - CsI= - """, - """ - MIHCMF4GCSqGSIb3DQEFDTBRMDAGCSqGSIb3DQEFDDAjBBDs2gn3woHJ+XwdWuSd - 46RbAgECMAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAECBBBH/zvMOoERHMs7UzaV - 4U3mBGCmDLZD82utm34xSHYt6XrtOIWhi/iPCR+em0mVSdPa1oIkDCoycK2UHKWM - G4RHjzl8wm27bQI9bmVD1bsLmY/pO971kwXFNi2+9nlEZ/JiG73oIRp3uodHEFN1 - jrlHKtI= - """, - "PLACEHOLDER", - new PbeParameters( - encryptionAlgorithm: PbeEncryptionAlgorithm.Aes128Cbc, - hashAlgorithm: HashAlgorithmName.SHA256, - iterationCount: 2 - )), - new(Id: 3, - SlhDsaAlgorithm.SlhDsaShake128s, - """ - D7C818DD88878021868FC8C613A2CB2FDF1B91A4496FE9ABDD15BD927715AECE186B2644B1E4FD9D1DCB61F73717ABFEF8876852095665E3F4A4A523A7B60E04 - """, - """ - MFICAQAwCwYJYIZIAWUDBAMaBEDXyBjdiIeAIYaPyMYTossv3xuRpElv6avdFb2S - dxWuzhhrJkSx5P2dHcth9zcXq/74h2hSCVZl4/SkpSOntg4E - """, - """ - MDAwCwYJYIZIAWUDBAMaAyEAGGsmRLHk/Z0dy2H3Nxer/viHaFIJVmXj9KSlI6e2 - DgQ= - """, - """ - MIHCMF4GCSqGSIb3DQEFDTBRMDAGCSqGSIb3DQEFDDAjBBAslxHfGLOzACYKLMNk - ONXGAgEKMAwGCCqGSIb3DQIKBQAwHQYJYIZIAWUDBAEWBBASfyUHTMmFQRd1G1Ex - g6C+BGCNJaYmrYhNwgCxmYCw/fSPe6loeHtcirwQ1/jVQS0y+pQlmUMQ4NpWcP3m - 3uFuO4O2zz1ZcHhQ6ZZcJBGloU6TCIiGXAjEWDh+8W0kpEnT8uHgb3KadrxXhpDt - 7tk2iuA= - """, - "PLACEHOLDER", - new PbeParameters( - encryptionAlgorithm: PbeEncryptionAlgorithm.Aes192Cbc, - hashAlgorithm: HashAlgorithmName.SHA384, - iterationCount: 10 - )), - new(Id: 4, - SlhDsaAlgorithm.SlhDsaShake128f, - """ - B279E3A491319B563C5F821D65ABF3A124161F6F4948958E2A67DC0761C1DFBF97072EA71E2994560FBB224DE5896626910F955A26E18D5651E93FE974DA2AFB - """, - """ - MFICAQAwCwYJYIZIAWUDBAMbBECyeeOkkTGbVjxfgh1lq/OhJBYfb0lIlY4qZ9wH - YcHfv5cHLqceKZRWD7siTeWJZiaRD5VaJuGNVlHpP+l02ir7 - """, - """ - MDAwCwYJYIZIAWUDBAMbAyEAlwcupx4plFYPuyJN5YlmJpEPlVom4Y1WUek/6XTa - Kvs= - """, - """ - MIHCMF4GCSqGSIb3DQEFDTBRMDAGCSqGSIb3DQEFDDAjBBDwceSe6+zBgBobw+lm - W5FvAgFkMAwGCCqGSIb3DQILBQAwHQYJYIZIAWUDBAEqBBCE8ynvzfdqZgi2uEyZ - pd4aBGCQRE3iX2KcaqNaJ1tu4EDD+4WV/r9f8jvl4ej9ADV3uCoG0V+yjiE/SlRS - dUy7od5lLc89BVV+B9xWEfuGJtmzDOl/PMiIpHxJqawuHPVNyMYcY3C5F12dunJC - 5N5j8ms= - """, - "PLACEHOLDER", - new PbeParameters( - encryptionAlgorithm: PbeEncryptionAlgorithm.Aes256Cbc, - hashAlgorithm: HashAlgorithmName.SHA512, - iterationCount: 100 - )), - new(Id: 5, - SlhDsaAlgorithm.SlhDsaSha2_192s, - """ - C708B21BE93C34C9C4C99199442B5497A3EB03833BCBD3807A46661B886906413597CDDA7D081B722D6C0F4FAFEC5DDD461F70365E0AF04B2A2F8B21618DD3561F0336282A6594624BF8DD5DCF2624C486BD53DEF76C78125AF810192A96DD74 - """, - """ - MHICAQAwCwYJYIZIAWUDBAMWBGDHCLIb6Tw0ycTJkZlEK1SXo+sDgzvL04B6RmYb - iGkGQTWXzdp9CBtyLWwPT6/sXd1GH3A2XgrwSyoviyFhjdNWHwM2KCpllGJL+N1d - zyYkxIa9U973bHgSWvgQGSqW3XQ= - """, - """ - MEAwCwYJYIZIAWUDBAMWAzEARh9wNl4K8EsqL4shYY3TVh8DNigqZZRiS/jdXc8m - JMSGvVPe92x4Elr4EBkqlt10 - """, - """ - MIHVMFAGCSqGSIb3DQEFDTBDMCIGCSqGSIb3DQEFDDAVBBDPmHPklMJHKCNchIHx - 2lGvAgEBMB0GCWCGSAFlAwQBAgQQivSOclukaqgvYwIYuvvRIgSBgDVNJuhTymrE - 9fCpNcXJ6sHWo/4A4sC5jQrRdpcPuou2PI7q811h7frFgoygFiN2CeZQ5mt826JM - +DU/WsRBC3LkU3hR+tJ3RQfufCbo01t9ryx6BJ77/ZE8yMXD69431TdfnZamNBOd - 4H5xS47WwdAWxEQA/a0xHVexkDz/mATr - """, - "PLACEHOLDER", - new PbeParameters( - encryptionAlgorithm: PbeEncryptionAlgorithm.Aes128Cbc, - hashAlgorithm: HashAlgorithmName.SHA1, - iterationCount: 1 - )), - new(Id: 6, - SlhDsaAlgorithm.SlhDsaSha2_192f, - """ - 8159DE9FBB759DF1B7C0AE9942FFD6B95FF967B9E9266C06487EBE79C89478775FC1A1F9F387D68FA8E5E3DE51027F561C9E217B4F1514A7C84ABF53D69DC86CFA1F77E88B91694E841D13E8D2E9E1AF1052760F0B37710C87D802E0EE88599B - """, - """ - MHICAQAwCwYJYIZIAWUDBAMXBGCBWd6fu3Wd8bfArplC/9a5X/lnuekmbAZIfr55 - yJR4d1/Bofnzh9aPqOXj3lECf1YcniF7TxUUp8hKv1PWnchs+h936IuRaU6EHRPo - 0unhrxBSdg8LN3EMh9gC4O6IWZs= - """, - """ - MEAwCwYJYIZIAWUDBAMXAzEAHJ4he08VFKfISr9T1p3IbPofd+iLkWlOhB0T6NLp - 4a8QUnYPCzdxDIfYAuDuiFmb - """, - """ - MIHjMF4GCSqGSIb3DQEFDTBRMDAGCSqGSIb3DQEFDDAjBBCOKi1XCW6Lo4TnBThS - sIlcAgECMAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEWBBBxD0O5JejO0+KAaDJ+ - 0P7TBIGAGZ3HJ4ja+KG9RceWYEOba2p17aFSFBjQ7kZ8AqHKzInJo6XrMn2Mk7IR - NhETOPDbRZzJChIajP3+Q024hCO/x8SC4Qk97jByt7xqEs8pTZTbr6ZpuPln7MzC - n5oXKhCm9d3KLa2y2oVKZyfz44I6/mzhD3+bA84yt+SE3044yck= - """, - "PLACEHOLDER", - new PbeParameters( - encryptionAlgorithm: PbeEncryptionAlgorithm.Aes192Cbc, - hashAlgorithm: HashAlgorithmName.SHA256, - iterationCount: 2 - )), - new(Id: 7, - SlhDsaAlgorithm.SlhDsaShake192s, - """ - D921298494DB837D9B450F7739FFA661904C371520FA1F6C61FE69E10D366EE7E459D613CD2D7E39FAE56FFAD192E43227FB0A060ADAEC5ED5FBC539189FF2FFF1005D0D81D08A510E41675B90F38C431F7DBDE5FF09E6F6829EF80B7E93F1B9 - """, - """ - MHICAQAwCwYJYIZIAWUDBAMcBGDZISmElNuDfZtFD3c5/6ZhkEw3FSD6H2xh/mnh - DTZu5+RZ1hPNLX45+uVv+tGS5DIn+woGCtrsXtX7xTkYn/L/8QBdDYHQilEOQWdb - kPOMQx99veX/Ceb2gp74C36T8bk= - """, - """ - MEAwCwYJYIZIAWUDBAMcAzEAJ/sKBgra7F7V+8U5GJ/y//EAXQ2B0IpRDkFnW5Dz - jEMffb3l/wnm9oKe+At+k/G5 - """, - """ - MIHjMF4GCSqGSIb3DQEFDTBRMDAGCSqGSIb3DQEFDDAjBBDy/gue9NWH3Xco4ptD - eRuuAgEKMAwGCCqGSIb3DQIKBQAwHQYJYIZIAWUDBAEqBBCf8t6aLcGDkBetMXSA - 70T7BIGAi+RKcyNzUfyARLV7EFREqPgQlabXwJB6wxXZ/AGcGr+uczqPyVqbJQQH - 6MaLZFBdDwa6PDxL56FFpeGVaLA4gPYn1K1jBxdm/dsZO+Y5rh+f9N1wOfY7gHt/ - N7rnhtxlgsptD+yOyCldibrxY2BTQVHf8xFO0wx3pYF/eXw6gLM= - """, - "PLACEHOLDER", - new PbeParameters( - encryptionAlgorithm: PbeEncryptionAlgorithm.Aes256Cbc, - hashAlgorithm: HashAlgorithmName.SHA384, - iterationCount: 10 - )), - new(Id: 8, - SlhDsaAlgorithm.SlhDsaShake192f, - """ - D3EAF7DDBFF77633200D54EC276A016F489AF36456DD66A674F1E174486F2D3C66A883A2044B4FB7A074FA0FF077DDC11D4BA0989C1AB04357798DFA475FC37A177127C6EBB02A7772AC6363C185EFDA75B1B46E8EA9C89BF711C4133578C79F - """, - """ - MHICAQAwCwYJYIZIAWUDBAMdBGDT6vfdv/d2MyANVOwnagFvSJrzZFbdZqZ08eF0 - SG8tPGaog6IES0+3oHT6D/B33cEdS6CYnBqwQ1d5jfpHX8N6F3EnxuuwKndyrGNj - wYXv2nWxtG6Oqcib9xHEEzV4x58= - """, - """ - MEAwCwYJYIZIAWUDBAMdAzEAHUugmJwasENXeY36R1/DehdxJ8brsCp3cqxjY8GF - 79p1sbRujqnIm/cRxBM1eMef - """, - """ - MIHjMF4GCSqGSIb3DQEFDTBRMDAGCSqGSIb3DQEFDDAjBBCqoplnb1Vt/wG1Pi8S - wDzdAgFkMAwGCCqGSIb3DQILBQAwHQYJYIZIAWUDBAECBBBHn/9ZbzARLnZyyMsF - lCYxBIGAwJ6Fdu3mVOBqXT/s220rhC49aTYv5dPOrPQ5IP8k8D8aFdnDgEQYdClU - Qyo5i4mRyKuZWKZDMdT0A3m/Z6gvuCf6utLDY4sCNmr4/jrBwFXUFMTKQv5/Xyxe - nehAUiLiL6ap11Qh73PyPHNTHDn5uripEy9qj3xO6egEcwXElSg= - """, - "PLACEHOLDER", - new PbeParameters( - encryptionAlgorithm: PbeEncryptionAlgorithm.Aes128Cbc, - hashAlgorithm: HashAlgorithmName.SHA512, - iterationCount: 100 - )), - new(Id: 9, - SlhDsaAlgorithm.SlhDsaSha2_256s, - """ - D4DA43D67222BCA119E5EAAF14FD72F8C48933CA492533929915A38A8873EBFF19BF55E30758CD3918062B6E2F7ABC8F3CE99274991E704959F4B28B1F2A565778BE022EB7DBE11E399F520ED942C3E0671710D783E1D3EEFCEAD9513BE0984C8635795CFAEC3F13E4E63F1BFB997CCF7ECEED5E40515D2B96D66CEBA7C8A7CE - """, - """ - MIGTAgEAMAsGCWCGSAFlAwQDGASBgNTaQ9ZyIryhGeXqrxT9cvjEiTPKSSUzkpkV - o4qIc+v/Gb9V4wdYzTkYBituL3q8jzzpknSZHnBJWfSyix8qVld4vgIut9vhHjmf - Ug7ZQsPgZxcQ14Ph0+786tlRO+CYTIY1eVz67D8T5OY/G/uZfM9+zu1eQFFdK5bW - bOunyKfO - """, - """ - MFAwCwYJYIZIAWUDBAMYA0EAeL4CLrfb4R45n1IO2ULD4GcXENeD4dPu/OrZUTvg - mEyGNXlc+uw/E+TmPxv7mXzPfs7tXkBRXSuW1mzrp8inzg== - """, - """ - MIH1MFAGCSqGSIb3DQEFDTBDMCIGCSqGSIb3DQEFDDAVBBAqk/MINddvR4Y9Bn6B - HuwgAgEBMB0GCWCGSAFlAwQBFgQQNf1lNMG32NBGuJfCA7ltxgSBoIt7NeIibVjN - nv8pAXhzkHUCDZD8SzIkXUvG24zMZDJlr+dCkN4eATmvwK2lmRArRYqnOxhYiNMr - Zqb4OS7GQWlvt3kcCtFoFtIuExax6q3HxhI79Fpib/imFtsbduE1hDbp1Vkr7kS3 - pn+594l8WWiLPYG6El61NEZa+kLKPdxE+PImyvmslSsR62BlkTGqOGEDi44mQwSO - wHTG1JqEDOY= - """, - "PLACEHOLDER", - new PbeParameters( - encryptionAlgorithm: PbeEncryptionAlgorithm.Aes192Cbc, - hashAlgorithm: HashAlgorithmName.SHA1, - iterationCount: 1 - )), - new(Id: 10, - SlhDsaAlgorithm.SlhDsaSha2_256f, - """ - 96CD870D38B9439A8D3DD11DE9D401309D1C50022AE1B290A129B22A80A72418125D2BDB48FD509F60640C5C8AD5957000C38B264C6EAF9BE5BB2D2FEC52771D07A1E63AAC5A48B5B27EE2B46B92352EA9F1F66A14B73AF60E3BEA1A73D74FB653DD29E94A3426A280932B5321065EF158BDFEA4F7916FAA321DD0369BE9BFDF - """, - """ - MIGTAgEAMAsGCWCGSAFlAwQDGQSBgJbNhw04uUOajT3RHenUATCdHFACKuGykKEp - siqApyQYEl0r20j9UJ9gZAxcitWVcADDiyZMbq+b5bstL+xSdx0HoeY6rFpItbJ+ - 4rRrkjUuqfH2ahS3OvYOO+oac9dPtlPdKelKNCaigJMrUyEGXvFYvf6k95FvqjId - 0Dab6b/f - """, - """ - MFAwCwYJYIZIAWUDBAMZA0EAB6HmOqxaSLWyfuK0a5I1Lqnx9moUtzr2DjvqGnPX - T7ZT3SnpSjQmooCTK1MhBl7xWL3+pPeRb6oyHdA2m+m/3w== - """, - """ - MIIBAzBeBgkqhkiG9w0BBQ0wUTAwBgkqhkiG9w0BBQwwIwQQf5XFHo/Sia09Zv0J - BKmmhwIBAjAMBggqhkiG9w0CCQUAMB0GCWCGSAFlAwQBKgQQVzpIYsjA8A2KcNFF - 9eJ1iASBoOkJhdEAfNfWrhTDpX07T6nPG1z/jKNEbFDsf3/4tfuUBL0/LJzxE2dM - 54KBsFRrFNUmyqnZQTzNd6tGbzsInPwj9AyrLFoOSCeOjc0nPYhb+okWevLZTqbT - 3YphKC4BojG2e9lfqbRkHmDoSU3szIRMCdlNPUsK0lJ6nBdH6Q14khYOCM4afB6S - JTbT/dRJwXmOfg8+Hw3pFFfNn01IQUM= - """, - "PLACEHOLDER", - new PbeParameters( - encryptionAlgorithm: PbeEncryptionAlgorithm.Aes256Cbc, - hashAlgorithm: HashAlgorithmName.SHA256, - iterationCount: 2 - )), - new(Id: 11, - SlhDsaAlgorithm.SlhDsaShake256s, - """ - 919C246F4A18DBD4CA2F793DAAD46FD2DF258E2B17620C671D28731AB1000B0BA321DD91D0D3F030AD176022ED3C1708D0ABBFF9B3DA4963759FEA19CDFD6F82BF6AFAFACAE725947F1CE882BF7570CF6925C2F4035526E620DE31EA86B2C135C2AF1640D489BFA859097B7E167D7ED4C1D59A77A07F216B75D8A91C97B36F65 - """, - """ - MIGTAgEAMAsGCWCGSAFlAwQDHgSBgJGcJG9KGNvUyi95ParUb9LfJY4rF2IMZx0o - cxqxAAsLoyHdkdDT8DCtF2Ai7TwXCNCrv/mz2kljdZ/qGc39b4K/avr6yucllH8c - 6IK/dXDPaSXC9ANVJuYg3jHqhrLBNcKvFkDUib+oWQl7fhZ9ftTB1Zp3oH8ha3XY - qRyXs29l - """, - """ - MFAwCwYJYIZIAWUDBAMeA0EAv2r6+srnJZR/HOiCv3Vwz2klwvQDVSbmIN4x6oay - wTXCrxZA1Im/qFkJe34WfX7UwdWad6B/IWt12Kkcl7NvZQ== - """, - """ - MIIBAzBeBgkqhkiG9w0BBQ0wUTAwBgkqhkiG9w0BBQwwIwQQWAf7+Aceksz/iDop - fk51+gIBCjAMBggqhkiG9w0CCgUAMB0GCWCGSAFlAwQBAgQQRFAwkKXFMyKBYtsK - jqFiGQSBoFAivVOrpQEPUaM49n+seHukP5zfzO2kdjdOkqQ3RwSlCHDoZ7i83Wo6 - iVRFC7B0AtWjv68B8uJY91ktpqlcBDPyBUERZmlbkt8GGONHrskKPpf7HshXGEbQ - KXn50fr3r37NwjKI+1dtpzF03p3xc2zplU32dY9Gwsp4FV6yw+VJ2NvcSenNUV1N - hnG5jLHc/gesBRn7YF5w8imFM6gXGD0= - """, - "PLACEHOLDER", - new PbeParameters( - encryptionAlgorithm: PbeEncryptionAlgorithm.Aes128Cbc, - hashAlgorithm: HashAlgorithmName.SHA384, - iterationCount: 10 - )), - new(Id: 12, - SlhDsaAlgorithm.SlhDsaShake256f, - """ - 62A3B684533A6C6F83A24CE7A1E2B5AC878893AD2F941268BDEB8EAED359C49B15E918AE3133D9AD4DDB5B25905DC54F538F4F9DC7F5F002552C6536E2648CE5592157980057914E6299BD85B6EA539066EF20524239630C1AF97E3B3DEC4A03BCD2EFC42AB615D5258EB93CD933E0D73A34F66B4F3F66955A8B3F24D22EE61E - """, - """ - MIGTAgEAMAsGCWCGSAFlAwQDHwSBgGKjtoRTOmxvg6JM56HitayHiJOtL5QSaL3r - jq7TWcSbFekYrjEz2a1N21slkF3FT1OPT53H9fACVSxlNuJkjOVZIVeYAFeRTmKZ - vYW26lOQZu8gUkI5Ywwa+X47PexKA7zS78QqthXVJY65PNkz4Nc6NPZrTz9mlVqL - PyTSLuYe - """, - """ - MFAwCwYJYIZIAWUDBAMfA0EAWSFXmABXkU5imb2FtupTkGbvIFJCOWMMGvl+Oz3s - SgO80u/EKrYV1SWOuTzZM+DXOjT2a08/ZpVaiz8k0i7mHg== - """, - """ - MIIBAzBeBgkqhkiG9w0BBQ0wUTAwBgkqhkiG9w0BBQwwIwQQXk9CFcNC4Ihp5z0E - S6Iw+wIBZDAMBggqhkiG9w0CCwUAMB0GCWCGSAFlAwQBFgQQobVOYyOTAAzTgSX5 - pHOjKQSBoIBd/xmZJEp4rJvxTFY0TXt8epKY0FFPO8UlC8PD9T+nuBziaOm7oT8G - 6HlQa8iM5PmN/RCUhYXTFjFN0dy3641OubA+8uEfgVYwpg2WCUadHHlpu8BJKzUM - NgU1QzLZKuPyS9v4S5rRDJBXg2SCD31H2AyU5i9a/WDEbHysfSdKmmmqgMAXHhcW - jFVl5ekLEvfG8gnb7Xf16I91NZiSEec= - """, - "PLACEHOLDER", - new PbeParameters( - encryptionAlgorithm: PbeEncryptionAlgorithm.Aes192Cbc, - hashAlgorithm: HashAlgorithmName.SHA512, - iterationCount: 100 - )), - ]; - + public static partial SlhDsaGeneratedKeyInfo[] GeneratedKeyInfosRaw { get; } + public record SlhDsaKeyGenTestVector( int TestCaseId, SlhDsaAlgorithm Algorithm, diff --git a/src/runtime/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaTestHelpers.cs b/src/runtime/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaTestHelpers.cs index 4189208bfbd..ee292ec2398 100644 --- a/src/runtime/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaTestHelpers.cs +++ b/src/runtime/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaTestHelpers.cs @@ -12,6 +12,8 @@ namespace System.Security.Cryptography.SLHDsa.Tests { internal static class SlhDsaTestHelpers { + public static bool SlhDsaIsNotSupported => !SlhDsa.IsSupported; + // DER encoding of ASN.1 BitString "foo" internal static readonly ReadOnlyMemory s_derBitStringFoo = new byte[] { 0x03, 0x04, 0x00, 0x66, 0x6f, 0x6f }; diff --git a/src/runtime/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/CertificateAuthority.cs b/src/runtime/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/CertificateAuthority.cs index e820e639ade..6dbf5d47f16 100644 --- a/src/runtime/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/CertificateAuthority.cs +++ b/src/runtime/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/CertificateAuthority.cs @@ -998,6 +998,7 @@ internal static X509Certificate2 CloneWithPrivateKey(X509Certificate2 cert, obje RSA rsa => cert.CopyWithPrivateKey(rsa), ECDsa ecdsa => cert.CopyWithPrivateKey(ecdsa), MLDsa mldsa => cert.CopyWithPrivateKey(mldsa), + SlhDsa slhDsa => cert.CopyWithPrivateKey(slhDsa), DSA dsa => cert.CopyWithPrivateKey(dsa), _ => throw new InvalidOperationException( $"Had no handler for key of type {key?.GetType().FullName ?? "null"}") diff --git a/src/runtime/src/libraries/Microsoft.Bcl.Cryptography/tests/Microsoft.Bcl.Cryptography.Tests.csproj b/src/runtime/src/libraries/Microsoft.Bcl.Cryptography/tests/Microsoft.Bcl.Cryptography.Tests.csproj index b4c01a7df20..0b65d647583 100644 --- a/src/runtime/src/libraries/Microsoft.Bcl.Cryptography/tests/Microsoft.Bcl.Cryptography.Tests.csproj +++ b/src/runtime/src/libraries/Microsoft.Bcl.Cryptography/tests/Microsoft.Bcl.Cryptography.Tests.csproj @@ -142,6 +142,8 @@ Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\SlhDsa\SlhDsaPlatformTests.cs" /> + - /// Supresses false-positive diagnostics emitted by the linker + /// Suppresses false-positive diagnostics emitted by the linker /// when analyzing binding invocations that we have intercepted. /// Workaround for https://github.com/dotnet/roslyn/issues/68669. /// diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs b/src/runtime/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs index 685850bb16e..ba4f4617d68 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs +++ b/src/runtime/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs @@ -1180,7 +1180,10 @@ private bool EmitObjectInit(ComplexTypeSpec type, string memberAccessExpr, Initi if (strategy is ObjectInstantiationStrategy.ParameterlessConstructor) { - initExpr = $"new {typeFQN}()"; + // value tuple types will be declared with syntax like: + // (int, int) value = default; + // This is to avoid using invalid syntax calling the parameterless constructor + initExpr = type.IsValueTuple ? "default" : $"new {typeFQN}()"; } else { @@ -1195,7 +1198,11 @@ private bool EmitObjectInit(ComplexTypeSpec type, string memberAccessExpr, Initi case InitializationKind.Declaration: { Debug.Assert(!memberAccessExpr.Contains('.')); - _writer.WriteLine($"var {memberAccessExpr} = {initExpr};"); + // value tuple will be declared with syntax like: + // (int, int) value = default; + // We need to specify the typeFQN as we assign the variable to default value. + string declarationType = type.IsValueTuple ? typeFQN : $"var"; + _writer.WriteLine($"{declarationType} {memberAccessExpr} = {initExpr};"); } break; case InitializationKind.AssignmentWithNullCheck: diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/TypeSpec.cs b/src/runtime/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/TypeSpec.cs index 69168edb58e..ac532f553ca 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/TypeSpec.cs +++ b/src/runtime/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Types/TypeSpec.cs @@ -17,6 +17,7 @@ public TypeSpec(ITypeSymbol type) (DisplayString, FullName) = type.GetTypeNames(); IdentifierCompatibleSubstring = type.ToIdentifierCompatibleSubstring(); IsValueType = type.IsValueType; + IsValueTuple = type is INamedTypeSymbol namedTypeSymbol && namedTypeSymbol.IsTupleType; } public TypeRef TypeRef { get; } @@ -36,6 +37,8 @@ public TypeSpec(ITypeSymbol type) public string IdentifierCompatibleSubstring { get; } public bool IsValueType { get; } + + public bool IsValueTuple { get; } } public abstract record ComplexTypeSpec : TypeSpec diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs b/src/runtime/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs index 19c170bfcd4..2a79ea181c8 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs +++ b/src/runtime/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs @@ -202,5 +202,18 @@ private static HashSet GetFilteredAssemblyRefs(IEnumerable exclu } return assemblies; } + + public static byte[] CreateAssemblyImage(Compilation compilation) + { + MemoryStream ms = new MemoryStream(); + var emitResult = compilation.Emit(ms); + if (!emitResult.Success) + { + // Explicit failures to include in the test output. + string errorMessage = string.Join(Environment.NewLine, emitResult.Diagnostics.Select(d => d.ToString())); + throw new InvalidOperationException(errorMessage); + } + return ms.ToArray(); + } } } diff --git a/src/runtime/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs b/src/runtime/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs index 1442c623f3f..00a038bdf5c 100644 --- a/src/runtime/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs +++ b/src/runtime/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs @@ -257,6 +257,43 @@ async Task Test(bool expectOutput) } } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task ListOfTupleTest() + { + string source = """ + using Microsoft.Extensions.Configuration; + using System; + using System.Collections.Generic; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfiguration config = configurationBuilder.Build(); + + var settingsSection = config.GetSection("Settings"); + + Settings options = settingsSection.Get()!; + } + } + + public class Settings + { + public List<(string Item1, string? Item2)>? Items { get; set; } + } + """; + + ConfigBindingGenRunResult result = await RunGeneratorAndUpdateCompilation(source, assemblyReferences: GetAssemblyRefsWithAdditional(typeof(ConfigurationBuilder), typeof(List<>))); + Assert.NotNull(result.GeneratedSource); + Assert.Empty(result.Diagnostics); + + // Ensure the generated code can be compiled. + // If there is any compilation error, exception will be thrown with the list of the errors in the exception message. + byte[] emittedAssemblyImage = CreateAssemblyImage(result.OutputCompilation); + Assert.NotNull(emittedAssemblyImage); + } + /// /// We binding the type "SslClientAuthenticationOptions" which has a property "CipherSuitesPolicy" of type "CipherSuitesPolicy". We can't bind this type. /// This test is to ensure not including the property "CipherSuitesPolicy" in the generated code caused a build break. diff --git a/src/runtime/src/libraries/Microsoft.NETCore.Platforms/src/Microsoft.NETCore.Platforms.csproj b/src/runtime/src/libraries/Microsoft.NETCore.Platforms/src/Microsoft.NETCore.Platforms.csproj index 84e378bd855..a588bccee0f 100644 --- a/src/runtime/src/libraries/Microsoft.NETCore.Platforms/src/Microsoft.NETCore.Platforms.csproj +++ b/src/runtime/src/libraries/Microsoft.NETCore.Platforms/src/Microsoft.NETCore.Platforms.csproj @@ -18,12 +18,22 @@ <_generateRuntimeGraphTargetFramework Condition="'$(MSBuildRuntimeType)' == 'core'">$(NetCoreAppToolCurrent) <_generateRuntimeGraphTargetFramework Condition="'$(MSBuildRuntimeType)' != 'core'">$(NetFrameworkToolCurrent) <_generateRuntimeGraphTask>$([MSBuild]::NormalizePath('$(BaseOutputPath)', $(Configuration), '$(_generateRuntimeGraphTargetFramework)', '$(AssemblyName).dll')) + + + $(BaseOS) + $(AdditionalRuntimeIdentifierParent) + + + + + $(NETCoreSdkPortableRuntimeIdentifier) - + diff --git a/src/runtime/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/UrlAttribute.cs b/src/runtime/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/UrlAttribute.cs index 91e8e40494f..830b36fcbbd 100644 --- a/src/runtime/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/UrlAttribute.cs +++ b/src/runtime/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/UrlAttribute.cs @@ -19,7 +19,7 @@ public override bool IsValid(object? value) { switch (value) { - case Uri valueAsUri: + case Uri valueAsUri when valueAsUri.IsAbsoluteUri: { return valueAsUri.Scheme == Uri.UriSchemeHttp || valueAsUri.Scheme == Uri.UriSchemeHttps diff --git a/src/runtime/src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/UrlAttributeTests.cs b/src/runtime/src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/UrlAttributeTests.cs index 0b674ddff6d..e137ce077e6 100644 --- a/src/runtime/src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/UrlAttributeTests.cs +++ b/src/runtime/src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/UrlAttributeTests.cs @@ -26,6 +26,8 @@ protected override IEnumerable InvalidValues() yield return new TestCase(new UrlAttribute(), new object()); yield return new TestCase(new UrlAttribute(), new Uri("file:///foo.bar")); yield return new TestCase(new UrlAttribute(), new Uri("//foo.png")); + yield return new TestCase(new UrlAttribute(), new Uri("/foo.png", UriKind.RelativeOrAbsolute)); + yield return new TestCase(new UrlAttribute(), new Uri("foo.png", UriKind.Relative)); } [Fact] diff --git a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Base64Stream.cs b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Base64Stream.cs index e279a5b4b2f..83dfbb84cf0 100644 --- a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Base64Stream.cs +++ b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Base64Stream.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using System.Buffers; namespace System.Net { @@ -20,7 +21,7 @@ internal sealed class Base64Stream : DelegatedStream, IEncodableStream 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, // 2 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, // 3 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 4 - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, // 5 + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, // 5 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 6 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, // 7 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 8 @@ -52,6 +53,9 @@ internal Base64Stream(Base64WriteStateInfo writeStateInfo) : base(new MemoryStre _encoder = new Base64Encoder(_writeState, writeStateInfo.MaxLineLength); } + public override bool CanRead => BaseStream.CanRead; + public override bool CanWrite => BaseStream.CanWrite; + private ReadStateInfo ReadState => _readState ??= new ReadStateInfo(); internal WriteStateInfoBase WriteState @@ -63,12 +67,6 @@ internal WriteStateInfoBase WriteState } } - public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) => - TaskToAsyncResult.Begin(ReadAsync(buffer, offset, count, CancellationToken.None), callback, state); - - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) => - TaskToAsyncResult.Begin(WriteAsync(buffer, offset, count, CancellationToken.None), callback, state); - public override void Close() { if (_writeState != null && WriteState.Length > 0) @@ -80,14 +78,14 @@ public override void Close() base.Close(); } - public unsafe int DecodeBytes(byte[] buffer, int offset, int count) + public unsafe int DecodeBytes(Span buffer) { fixed (byte* pBuffer = buffer) { - byte* start = pBuffer + offset; + byte* start = pBuffer; byte* source = start; byte* dest = start; - byte* end = start + count; + byte* end = start + buffer.Length; while (source < end) { @@ -133,24 +131,18 @@ public unsafe int DecodeBytes(byte[] buffer, int offset, int count) } } - public int EncodeBytes(byte[] buffer, int offset, int count) => - EncodeBytes(buffer, offset, count, true, true); + public int EncodeBytes(ReadOnlySpan buffer) => + _encoder.EncodeBytes(buffer, true, true); - internal int EncodeBytes(byte[] buffer, int offset, int count, bool dontDeferFinalBytes, bool shouldAppendSpaceToCRLF) + internal int EncodeBytes(ReadOnlySpan buffer, bool dontDeferFinalBytes, bool shouldAppendSpaceToCRLF) { - return _encoder.EncodeBytes(buffer, offset, count, dontDeferFinalBytes, shouldAppendSpaceToCRLF); + return _encoder.EncodeBytes(buffer, dontDeferFinalBytes, shouldAppendSpaceToCRLF); } public int EncodeString(string value, Encoding encoding) => _encoder.EncodeString(value, encoding); public string GetEncodedString() => _encoder.GetEncodedString(); - public override int EndRead(IAsyncResult asyncResult) => - TaskToAsyncResult.End(asyncResult); - - public override void EndWrite(IAsyncResult asyncResult) => - TaskToAsyncResult.End(asyncResult); - public override void Flush() { if (_writeState != null && WriteState.Length > 0) @@ -163,90 +155,78 @@ public override void Flush() public override async Task FlushAsync(CancellationToken cancellationToken) { - if (_writeState != null && WriteState.Length > 0) - { - await base.WriteAsync(WriteState.Buffer.AsMemory(0, WriteState.Length), cancellationToken).ConfigureAwait(false); - WriteState.Reset(); - } - + await FlushInternalAsync(cancellationToken).ConfigureAwait(false); await base.FlushAsync(cancellationToken).ConfigureAwait(false); } private void FlushInternal() { - base.Write(WriteState.Buffer, 0, WriteState.Length); + BaseStream.Write(WriteState.Buffer.AsSpan(0, WriteState.Length)); WriteState.Reset(); } - public override int Read(byte[] buffer, int offset, int count) + private async ValueTask FlushInternalAsync(CancellationToken cancellationToken) { - ValidateBufferArguments(buffer, offset, count); + await BaseStream.WriteAsync(WriteState.Buffer.AsMemory(0, WriteState.Length), cancellationToken).ConfigureAwait(false); + WriteState.Reset(); + } + protected override int ReadInternal(Span buffer) + { while (true) { // read data from the underlying stream - int read = base.Read(buffer, offset, count); + int read = BaseStream.Read(buffer); // if the underlying stream returns 0 then there - // is no more data - ust return 0. + // is no more data - just return 0. if (read == 0) { return 0; } - // while decoding, we may end up not having - // any bytes to return pending additional data - // from the underlying stream. - read = DecodeBytes(buffer, offset, read); + // Decode the read bytes and update the input buffer with decoded bytes + read = DecodeBytes(buffer.Slice(0, read)); if (read > 0) { return read; } } } - public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - ValidateBufferArguments(buffer, offset, count); - return ReadAsyncCore(buffer, offset, count, cancellationToken); - async Task ReadAsyncCore(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + protected override async ValueTask ReadAsyncInternal(Memory buffer, CancellationToken cancellationToken = default) + { + while (true) { - while (true) - { - // read data from the underlying stream - int read = await base.ReadAsync(buffer.AsMemory(offset, count), cancellationToken).ConfigureAwait(false); + // read data from the underlying stream + int read = await BaseStream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false); - // if the underlying stream returns 0 then there - // is no more data - ust return 0. - if (read == 0) - { - return 0; - } + // if the underlying stream returns 0 then there + // is no more data - just return 0. + if (read == 0) + { + return 0; + } - // while decoding, we may end up not having - // any bytes to return pending additional data - // from the underlying stream. - read = DecodeBytes(buffer, offset, read); - if (read > 0) - { - return read; - } + // Decode the read bytes and update the input buffer with decoded bytes + read = DecodeBytes(buffer.Span.Slice(0, read)); + if (read > 0) + { + return read; } } } - public override void Write(byte[] buffer, int offset, int count) + protected override void WriteInternal(ReadOnlySpan buffer) { - ValidateBufferArguments(buffer, offset, count); - int written = 0; // do not append a space when writing from a stream since this means // it's writing the email body while (true) { - written += EncodeBytes(buffer, offset + written, count - written, false, false); - if (written < count) + written += EncodeBytes(buffer.Slice(written), false, false); + if (written < buffer.Length) { FlushInternal(); } @@ -257,28 +237,22 @@ public override void Write(byte[] buffer, int offset, int count) } } - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + protected override async ValueTask WriteAsyncInternal(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) { - ValidateBufferArguments(buffer, offset, count); - return WriteAsyncCore(buffer, offset, count, cancellationToken); + int written = 0; - async Task WriteAsyncCore(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + // do not append a space when writing from a stream since this means + // it's writing the email body + while (true) { - int written = 0; - - // do not append a space when writing from a stream since this means - // it's writing the email body - while (true) + written += EncodeBytes(buffer.Span.Slice(written), false, false); + if (written < buffer.Length) { - written += EncodeBytes(buffer, offset + written, count - written, false, false); - if (written < count) - { - await FlushAsync(cancellationToken).ConfigureAwait(false); - } - else - { - break; - } + await FlushInternalAsync(cancellationToken).ConfigureAwait(false); + } + else + { + break; } } } diff --git a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/BufferedReadStream.cs b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/BufferedReadStream.cs index 5e635d6d531..a760d2113c7 100644 --- a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/BufferedReadStream.cs +++ b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/BufferedReadStream.cs @@ -4,6 +4,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; +using System.Buffers; namespace System.Net { @@ -23,96 +24,76 @@ internal BufferedReadStream(Stream stream, bool readMore) : base(stream) _readMore = readMore; } - public override bool CanWrite - { - get - { - return false; - } - } + public override bool CanWrite => false; + public override bool CanRead => BaseStream.CanRead; - public override bool CanSeek - { - get - { - return false; - } - } - - public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) => - TaskToAsyncResult.Begin(ReadAsync(buffer, offset, count, CancellationToken.None), callback, state); + public override bool CanSeek => false; - public override int EndRead(IAsyncResult asyncResult) => - TaskToAsyncResult.End(asyncResult); - - public override int Read(byte[] buffer, int offset, int count) + protected override int ReadInternal(Span buffer) { - int read = 0; if (_storedOffset < _storedLength) { - read = Math.Min(count, _storedLength - _storedOffset); - Buffer.BlockCopy(_storedBuffer!, _storedOffset, buffer, offset, read); + int read = Math.Min(buffer.Length, _storedLength - _storedOffset); + _storedBuffer.AsSpan(_storedOffset, read).CopyTo(buffer); _storedOffset += read; - if (read == count || !_readMore) + if (read == buffer.Length || !_readMore) { return read; } - offset += read; - count -= read; + // Need to read more from the underlying stream + return read + BaseStream.Read(buffer.Slice(read)); } - return read + base.Read(buffer, offset, count); + + return BaseStream.Read(buffer); } - public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + protected override ValueTask ReadAsyncInternal(Memory buffer, CancellationToken cancellationToken = default) { - int read; if (_storedOffset >= _storedLength) { - return base.ReadAsync(buffer, offset, count, cancellationToken); + return BaseStream.ReadAsync(buffer, cancellationToken); } - read = Math.Min(count, _storedLength - _storedOffset); - Buffer.BlockCopy(_storedBuffer!, _storedOffset, buffer, offset, read); + int read = Math.Min(buffer.Length, _storedLength - _storedOffset); + _storedBuffer.AsMemory(_storedOffset, read).CopyTo(buffer); _storedOffset += read; - if (read == count || !_readMore) + if (read == buffer.Length || !_readMore) { - return Task.FromResult(read); + return new ValueTask(read); } - offset += read; - count -= read; - - return ReadMoreAsync(read, buffer, offset, count, cancellationToken); + // Need to read more from the underlying stream + return ReadMoreAsync(read, buffer.Slice(read), cancellationToken); } - private async Task ReadMoreAsync(int bytesAlreadyRead, byte[] buffer, int offset, int count, CancellationToken cancellationToken) + private async ValueTask ReadMoreAsync(int bytesAlreadyRead, Memory buffer, CancellationToken cancellationToken) { - int returnValue = await base.ReadAsync(buffer.AsMemory(offset, count), cancellationToken).ConfigureAwait(false); + int returnValue = await BaseStream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false); return bytesAlreadyRead + returnValue; } - public override int ReadByte() + protected override void WriteInternal(ReadOnlySpan buffer) { - if (_storedOffset < _storedLength) - { - return _storedBuffer![_storedOffset++]; - } - else - { - return base.ReadByte(); - } + throw new NotImplementedException(); + } + + protected override ValueTask WriteAsyncInternal(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); } // adds additional content to the beginning of the buffer // so the layout of the storedBuffer will be // // after calling push - internal void Push(byte[] buffer, int offset, int count) + internal void Push(ReadOnlySpan buffer) { - if (count == 0) + if (buffer.Length == 0) return; + int count = buffer.Length; + if (_storedOffset == _storedLength) { if (_storedBuffer == null || _storedBuffer.Length < count) @@ -146,7 +127,7 @@ internal void Push(byte[] buffer, int offset, int count) } } - Buffer.BlockCopy(buffer, offset, _storedBuffer!, _storedOffset, count); + buffer.CopyTo(_storedBuffer.AsSpan(_storedOffset)); } } } diff --git a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/CloseableStream.cs b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/CloseableStream.cs index adf9f88c0c1..e5455abf951 100644 --- a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/CloseableStream.cs +++ b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/CloseableStream.cs @@ -3,6 +3,7 @@ using System.IO; using System.Threading; +using System.Threading.Tasks; namespace System.Net { @@ -17,6 +18,9 @@ internal ClosableStream(Stream stream, EventHandler? onClose) : base(stream) _onClose = onClose; } + public override bool CanRead => BaseStream.CanRead; + public override bool CanWrite => BaseStream.CanWrite; + public override void Close() { if (Interlocked.Increment(ref _closed) == 1) @@ -24,5 +28,25 @@ public override void Close() _onClose?.Invoke(this, new EventArgs()); } } + + protected override void WriteInternal(ReadOnlySpan buffer) + { + BaseStream.Write(buffer); + } + + protected override ValueTask WriteAsyncInternal(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) + { + return BaseStream.WriteAsync(buffer, cancellationToken); + } + + protected override int ReadInternal(Span buffer) + { + return BaseStream.Read(buffer); + } + + protected override ValueTask ReadAsyncInternal(Memory buffer, CancellationToken cancellationToken = default) + { + return BaseStream.ReadAsync(buffer, cancellationToken); + } } } diff --git a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/DelegatedStream.cs b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/DelegatedStream.cs index d2321b3dfe2..1a8b3fa54cb 100644 --- a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/DelegatedStream.cs +++ b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/DelegatedStream.cs @@ -4,6 +4,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; +using System.Buffers; namespace System.Net { @@ -18,37 +19,13 @@ protected DelegatedStream(Stream stream) _stream = stream; } - protected Stream BaseStream - { - get - { - return _stream; - } - } + protected Stream BaseStream => _stream; - public override bool CanRead - { - get - { - return _stream.CanRead; - } - } + public override bool CanSeek => _stream.CanSeek; - public override bool CanSeek - { - get - { - return _stream.CanSeek; - } - } + public abstract override bool CanRead { get; } - public override bool CanWrite - { - get - { - return _stream.CanWrite; - } - } + public abstract override bool CanWrite { get; } public override long Length { @@ -79,43 +56,38 @@ public override long Position } } - public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) + public sealed override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) { - if (!CanRead) - throw new NotSupportedException(SR.ReadNotSupported); - - return _stream.BeginRead(buffer, offset, count, callback, state); + return TaskToAsyncResult.Begin(ReadAsync(buffer, offset, count, CancellationToken.None), callback, state); } - - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) + public sealed override int EndRead(IAsyncResult asyncResult) { - if (!CanWrite) - throw new NotSupportedException(SR.WriteNotSupported); - - return _stream.BeginWrite(buffer, offset, count, callback, state); + return TaskToAsyncResult.End(asyncResult); } - //This calls close on the inner stream - //however, the stream may not be actually closed, but simpy flushed - public override void Close() + public sealed override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) { - _stream.Close(); + return TaskToAsyncResult.Begin(WriteAsync(buffer, offset, count, CancellationToken.None), callback, state); } - public override int EndRead(IAsyncResult asyncResult) + public sealed override void EndWrite(IAsyncResult asyncResult) { - if (!CanRead) - throw new NotSupportedException(SR.ReadNotSupported); - - return _stream.EndRead(asyncResult); + TaskToAsyncResult.End(asyncResult); } - public override void EndWrite(IAsyncResult asyncResult) + public override void Close() { - if (!CanWrite) - throw new NotSupportedException(SR.WriteNotSupported); + _stream.Close(); + base.Close(); + } - _stream.EndWrite(asyncResult); + protected override void Dispose(bool disposing) + { + if (disposing) + { + _stream.Dispose(); + } + base.Dispose(disposing); } public override void Flush() @@ -128,31 +100,60 @@ public override Task FlushAsync(CancellationToken cancellationToken) return _stream.FlushAsync(cancellationToken); } - public override int Read(byte[] buffer, int offset, int count) + // Abstract methods for derived classes to implement core logic + protected abstract int ReadInternal(Span buffer); + + protected abstract ValueTask ReadAsyncInternal(Memory buffer, CancellationToken cancellationToken); + + protected abstract void WriteInternal(ReadOnlySpan buffer); + + protected abstract ValueTask WriteAsyncInternal(ReadOnlyMemory buffer, CancellationToken cancellationToken); + + // Sealed methods implementing the Stream Read/Write methods + public sealed override int Read(Span buffer) { if (!CanRead) throw new NotSupportedException(SR.ReadNotSupported); - return _stream.Read(buffer, offset, count); + return ReadInternal(buffer); } - public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + public sealed override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) { if (!CanRead) throw new NotSupportedException(SR.ReadNotSupported); - return _stream.ReadAsync(buffer, offset, count, cancellationToken); + return ReadAsyncInternal(buffer, cancellationToken); } - public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) + public sealed override int Read(byte[] buffer, int offset, int count) { + ValidateBufferArguments(buffer, offset, count); if (!CanRead) throw new NotSupportedException(SR.ReadNotSupported); - return _stream.ReadAsync(buffer, cancellationToken); + return ReadInternal(buffer.AsSpan(offset, count)); } - public override long Seek(long offset, SeekOrigin origin) + public sealed override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + ValidateBufferArguments(buffer, offset, count); + if (!CanRead) + throw new NotSupportedException(SR.ReadNotSupported); + + return ReadAsyncInternal(buffer.AsMemory(offset, count), cancellationToken).AsTask(); + } + + public sealed override int ReadByte() + { + if (!CanRead) + throw new NotSupportedException(SR.ReadNotSupported); + + byte b = 0; + return ReadInternal(new Span(ref b)) != 0 ? b : -1; + } + + public sealed override long Seek(long offset, SeekOrigin origin) { if (!CanSeek) throw new NotSupportedException(SR.SeekNotSupported); @@ -160,7 +161,7 @@ public override long Seek(long offset, SeekOrigin origin) return _stream.Seek(offset, origin); } - public override void SetLength(long value) + public sealed override void SetLength(long value) { if (!CanSeek) throw new NotSupportedException(SR.SeekNotSupported); @@ -168,28 +169,38 @@ public override void SetLength(long value) _stream.SetLength(value); } - public override void Write(byte[] buffer, int offset, int count) + public sealed override void Write(ReadOnlySpan buffer) + { + if (!CanWrite) + throw new NotSupportedException(SR.WriteNotSupported); + + WriteInternal(buffer); + } + + public sealed override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) { if (!CanWrite) throw new NotSupportedException(SR.WriteNotSupported); - _stream.Write(buffer, offset, count); + return WriteAsyncInternal(buffer, cancellationToken); } - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + public sealed override void Write(byte[] buffer, int offset, int count) { + ValidateBufferArguments(buffer, offset, count); if (!CanWrite) throw new NotSupportedException(SR.WriteNotSupported); - return _stream.WriteAsync(buffer, offset, count, cancellationToken); + WriteInternal(buffer.AsSpan(offset, count)); } - public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) + public sealed override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { + ValidateBufferArguments(buffer, offset, count); if (!CanWrite) throw new NotSupportedException(SR.WriteNotSupported); - return _stream.WriteAsync(buffer, cancellationToken); + return WriteAsyncInternal(buffer.AsMemory(offset, count), cancellationToken).AsTask(); } } } diff --git a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpReplyReaderFactory.cs b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpReplyReaderFactory.cs index dc60300bce1..03d32a7e44d 100644 --- a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpReplyReaderFactory.cs +++ b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpReplyReaderFactory.cs @@ -75,7 +75,7 @@ internal void Close(SmtpReplyReader caller) { _byteBuffer ??= new byte[SmtpReplyReaderFactory.DefaultBufferSize]; - while (0 != Read(caller, _byteBuffer, 0, _byteBuffer.Length)) ; + while (0 != Read(caller, _byteBuffer)) ; } _currentReader = null; @@ -106,10 +106,10 @@ internal SmtpReplyReader GetNextReplyReader() return _currentReader; } - private int ProcessRead(byte[] buffer, int offset, int read, bool readLine) + private int ProcessRead(ReadOnlySpan buffer, bool readLine) { // if 0 bytes were read,there was a failure - if (read == 0) + if (buffer.Length == 0) { throw new IOException(SR.Format(SR.net_io_readfailure, SR.net_io_connectionclosed)); } @@ -118,9 +118,9 @@ private int ProcessRead(byte[] buffer, int offset, int read, bool readLine) { fixed (byte* pBuffer = buffer) { - byte* start = pBuffer + offset; + byte* start = pBuffer; byte* ptr = start; - byte* end = ptr + read; + byte* end = ptr + buffer.Length; switch (_readState) { @@ -263,20 +263,20 @@ private int ProcessRead(byte[] buffer, int offset, int read, bool readLine) } } - internal int Read(SmtpReplyReader caller, byte[] buffer, int offset, int count) + internal int Read(SmtpReplyReader caller, Span buffer) { - // if we've already found the delimitter, then return 0 indicating + // if we've already found the delimiter, then return 0 indicating // end of stream. - if (count == 0 || _currentReader != caller || _readState == ReadState.Done) + if (buffer.Length == 0 || _currentReader != caller || _readState == ReadState.Done) { return 0; } - int read = _bufferedStream.Read(buffer, offset, count); - int actual = ProcessRead(buffer, offset, read, false); + int read = _bufferedStream.Read(buffer); + int actual = ProcessRead(buffer.Slice(0, read), false); if (actual < read) { - _bufferedStream.Push(buffer, offset + actual, read - actual); + _bufferedStream.Push(buffer.Slice(actual, read - actual)); } return actual; @@ -316,11 +316,11 @@ internal LineInfo[] ReadLines(SmtpReplyReader caller, bool oneLine) { if (start == read) { - read = _bufferedStream.Read(_byteBuffer, 0, _byteBuffer.Length); + read = _bufferedStream.Read(_byteBuffer); start = 0; } - int actual = ProcessRead(_byteBuffer, start, read - start, true); + int actual = ProcessRead(_byteBuffer.AsSpan(start, read), true); if (statusRead < 4) { @@ -344,7 +344,7 @@ internal LineInfo[] ReadLines(SmtpReplyReader caller, bool oneLine) if (oneLine) { - _bufferedStream.Push(_byteBuffer, start, read - start); + _bufferedStream.Push(_byteBuffer.AsSpan(start, read - start)); return lines.ToArray(); } builder = new StringBuilder(); @@ -352,7 +352,7 @@ internal LineInfo[] ReadLines(SmtpReplyReader caller, bool oneLine) else if (_readState == ReadState.Done) { lines.Add(new LineInfo(_statusCode, builder.ToString(0, builder.Length - 2))); // return everything except CRLF - _bufferedStream.Push(_byteBuffer, start, read - start); + _bufferedStream.Push(_byteBuffer.AsSpan(start, read - start)); return lines.ToArray(); } } @@ -454,7 +454,7 @@ private bool ProcessRead() for (int start = 0; start != _read;) { - int actual = _parent.ProcessRead(_parent._byteBuffer!, start, _read - start, true); + int actual = _parent.ProcessRead(_parent._byteBuffer!.AsSpan(start, _read - start), true); if (_statusRead < 4) { @@ -479,7 +479,7 @@ private bool ProcessRead() if (_oneLine) { - _parent._bufferedStream.Push(_parent._byteBuffer!, start, _read - start); + _parent._bufferedStream.Push(_parent._byteBuffer!.AsSpan(start, _read - start)); InvokeCallback(); return false; } @@ -487,7 +487,7 @@ private bool ProcessRead() else if (_parent._readState == ReadState.Done) { _lines!.Add(new LineInfo(_parent._statusCode, _builder.ToString(0, _builder.Length - 2))); // return everything except CRLF - _parent._bufferedStream.Push(_parent._byteBuffer!, start, _read - start); + _parent._bufferedStream.Push(_parent._byteBuffer!.AsSpan(start, _read - start)); InvokeCallback(); return false; } diff --git a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/Base64Encoder.cs b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/Base64Encoder.cs index 65dacb82da5..56e2cbe8f42 100644 --- a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/Base64Encoder.cs +++ b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/Base64Encoder.cs @@ -42,9 +42,9 @@ protected override bool LineBreakNeeded(byte b) return LineBreakNeeded(1); } - protected override bool LineBreakNeeded(byte[] bytes, int count) + protected override bool LineBreakNeeded(ReadOnlySpan bytes) { - return LineBreakNeeded(count); + return LineBreakNeeded(bytes.Length); } private bool LineBreakNeeded(int numberOfBytesToAppend) @@ -117,7 +117,7 @@ public override void AppendPadding() } } - protected override void ApppendEncodedByte(byte b) + protected override void AppendEncodedByte(byte b) { // Base64 encoding transforms a group of 3 bytes into a group of 4 Base64 characters switch (_writeState.Padding) diff --git a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/ByteEncoder.cs b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/ByteEncoder.cs index 0e7f6d964c2..9fca67e1ece 100644 --- a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/ByteEncoder.cs +++ b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/ByteEncoder.cs @@ -14,15 +14,15 @@ internal abstract class ByteEncoder : IByteEncoder public string GetEncodedString() => Encoding.ASCII.GetString(WriteState.Buffer, 0, WriteState.Length); - public int EncodeBytes(byte[] buffer, int offset, int count, bool dontDeferFinalBytes, bool shouldAppendSpaceToCRLF) + public int EncodeBytes(ReadOnlySpan buffer, bool dontDeferFinalBytes, bool shouldAppendSpaceToCRLF) { // Add Encoding header, if any. e.g. =?encoding?b? WriteState.AppendHeader(); bool _hasSpecialEncodingForCRLF = HasSpecialEncodingForCRLF; - int cur = offset; - for (; cur < count + offset; cur++) + int cur = 0; + for (; cur < buffer.Length; cur++) { if (LineBreakNeeded(buffer[cur])) { @@ -30,14 +30,14 @@ public int EncodeBytes(byte[] buffer, int offset, int count, bool dontDeferFinal WriteState.AppendCRLF(shouldAppendSpaceToCRLF); } - if (_hasSpecialEncodingForCRLF && IsCRLF(buffer, cur, count + offset)) + if (_hasSpecialEncodingForCRLF && buffer.Slice(cur).StartsWith("\r\n"u8)) { AppendEncodedCRLF(); cur++; // Transformed two chars, so shift the index to account for that } else { - ApppendEncodedByte(buffer[cur]); + AppendEncodedByte(buffer[cur]); } } @@ -48,7 +48,7 @@ public int EncodeBytes(byte[] buffer, int offset, int count, bool dontDeferFinal // Write out the last footer, if any. e.g. ?= WriteState.AppendFooter(); - return cur - offset; + return cur; } public int EncodeString(string value, Encoding encoding) @@ -57,10 +57,11 @@ public int EncodeString(string value, Encoding encoding) Debug.Assert(WriteState != null, "writestate was null"); Debug.Assert(WriteState.Buffer != null, "writestate.buffer was null"); + byte[] buffer; if (encoding == Encoding.Latin1) // we don't need to check for codepoints { - byte[] buffer = encoding.GetBytes(value); - return EncodeBytes(buffer, 0, buffer.Length, true, true); + buffer = encoding.GetBytes(value); + return EncodeBytes(buffer, true, true); } // Add Encoding header, if any. e.g. =?encoding?b? @@ -69,31 +70,33 @@ public int EncodeString(string value, Encoding encoding) bool _hasSpecialEncodingForCRLF = HasSpecialEncodingForCRLF; int totalBytesCount = 0; - byte[] bytes = new byte[encoding.GetMaxByteCount(2)]; + buffer = new byte[encoding.GetMaxByteCount(2)]; for (int i = 0; i < value.Length; ++i) { int codepointSize = GetCodepointSize(value, i); Debug.Assert(codepointSize == 1 || codepointSize == 2, "codepointSize was not 1 or 2"); - int bytesCount = encoding.GetBytes(value, i, codepointSize, bytes, 0); + int bytesCount = encoding.GetBytes(value, i, codepointSize, buffer, 0); + Span bytes = buffer.AsSpan(0, bytesCount); + if (codepointSize == 2) { ++i; // Transformed two chars, so shift the index to account for that } - if (LineBreakNeeded(bytes, bytesCount)) + if (LineBreakNeeded(bytes)) { AppendPadding(); WriteState.AppendCRLF(true); } - if (_hasSpecialEncodingForCRLF && IsCRLF(bytes, bytesCount)) + if (_hasSpecialEncodingForCRLF && IsCRLF(bytes)) { AppendEncodedCRLF(); } else { - AppendEncodedCodepoint(bytes, bytesCount); + AppendEncodedCodepoint(bytes); } totalBytesCount += bytesCount; } @@ -109,19 +112,19 @@ public int EncodeString(string value, Encoding encoding) protected abstract void AppendEncodedCRLF(); protected abstract bool LineBreakNeeded(byte b); - protected abstract bool LineBreakNeeded(byte[] bytes, int count); + protected abstract bool LineBreakNeeded(ReadOnlySpan bytes); protected abstract int GetCodepointSize(string value, int i); public abstract void AppendPadding(); - protected abstract void ApppendEncodedByte(byte b); + protected abstract void AppendEncodedByte(byte b); - private void AppendEncodedCodepoint(byte[] bytes, int count) + private void AppendEncodedCodepoint(ReadOnlySpan bytes) { - for (int i = 0; i < count; ++i) + foreach (byte b in bytes) { - ApppendEncodedByte(bytes[i]); + AppendEncodedByte(b); } } @@ -130,14 +133,9 @@ protected static bool IsSurrogatePair(string value, int i) return char.IsSurrogate(value[i]) && i + 1 < value.Length && char.IsSurrogatePair(value[i], value[i + 1]); } - protected static bool IsCRLF(byte[] bytes, int count) - { - return count == 2 && IsCRLF(bytes, 0, count); - } - - private static bool IsCRLF(byte[] buffer, int i, int bufferSize) + protected static bool IsCRLF(ReadOnlySpan buffer) { - return buffer[i] == '\r' && i + 1 < bufferSize && buffer[i + 1] == '\n'; + return buffer.SequenceEqual("\r\n"u8); } } } diff --git a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/EightBitStream.cs b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/EightBitStream.cs index f9aed4bc21e..ae92cf7aeb8 100644 --- a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/EightBitStream.cs +++ b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/EightBitStream.cs @@ -3,6 +3,9 @@ using System.IO; using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Buffers; namespace System.Net.Mime { @@ -43,59 +46,48 @@ internal EightBitStream(Stream stream, bool shouldEncodeLeadingDots) : this(stre _shouldEncodeLeadingDots = shouldEncodeLeadingDots; } - /// - /// Writes the specified content to the underlying stream - /// - /// Buffer to write - /// Offset within buffer to start writing - /// Count of bytes to write - /// Callback to call when write completes - /// State to pass to callback - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) + public override bool CanRead => false; + public override bool CanWrite => BaseStream.CanWrite; + + protected override int ReadInternal(Span buffer) { - ValidateBufferArguments(buffer, offset, count); + throw new NotImplementedException(); + } - IAsyncResult result; + protected override ValueTask ReadAsyncInternal(Memory buffer, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + // Implement abstract Write methods + protected override void WriteInternal(ReadOnlySpan buffer) + { if (_shouldEncodeLeadingDots) { - EncodeLines(buffer, offset, count); - result = base.BeginWrite(WriteState.Buffer, 0, WriteState.Length, callback, state); + EncodeLines(buffer); + BaseStream.Write(WriteState.Buffer.AsSpan(0, WriteState.Length)); + WriteState.BufferFlushed(); } else { // Note: for legacy reasons we are not enforcing buffer[i] <= 127. - result = base.BeginWrite(buffer, offset, count, callback, state); + BaseStream.Write(buffer); } - - return result; - } - - public override void EndWrite(IAsyncResult asyncResult) - { - base.EndWrite(asyncResult); - WriteState.BufferFlushed(); } - /// - /// Writes the specified content to the underlying stream - /// - /// Buffer to write - /// Offset within buffer to start writing - /// Count of bytes to write - public override void Write(byte[] buffer, int offset, int count) + protected override ValueTask WriteAsyncInternal(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) { - ValidateBufferArguments(buffer, offset, count); - if (_shouldEncodeLeadingDots) { - EncodeLines(buffer, offset, count); - base.Write(WriteState.Buffer, 0, WriteState.Length); - WriteState.BufferFlushed(); + EncodeLines(buffer.Span); + ValueTask task = BaseStream.WriteAsync(WriteState.Buffer.AsMemory(0, WriteState.Length), cancellationToken); + WriteState.BufferFlushed(); // Reset state after initiating async write + return task; } else { // Note: for legacy reasons we are not enforcing buffer[i] <= 127. - base.Write(buffer, offset, count); + return BaseStream.WriteAsync(buffer, cancellationToken); } } @@ -103,14 +95,14 @@ public override void Write(byte[] buffer, int offset, int count) // Despite not having to encode content, we still have to implement // RFC 2821 Section 4.5.2 about leading dots on a line - private void EncodeLines(byte[] buffer, int offset, int count) + private void EncodeLines(ReadOnlySpan buffer) { - for (int i = offset; (i < offset + count) && (i < buffer.Length); i++) + for (int i = 0; i < buffer.Length; i++) { // Note: for legacy reasons we are not enforcing buffer[i] <= 127. // Detect CRLF line endings - if ((buffer[i] == '\r') && ((i + 1) < (offset + count)) && (buffer[i + 1] == '\n')) + if ((buffer[i] == '\r') && ((i + 1) < buffer.Length) && (buffer[i + 1] == '\n')) { WriteState.AppendCRLF(false); // Resets CurrentLineLength to 0 i++; // Skip past the recorded CRLF @@ -130,9 +122,9 @@ private void EncodeLines(byte[] buffer, int offset, int count) } } - public int DecodeBytes(byte[] buffer, int offset, int count) { throw new NotImplementedException(); } + public int DecodeBytes(Span buffer) { throw new NotImplementedException(); } - public int EncodeBytes(byte[] buffer, int offset, int count) { throw new NotImplementedException(); } + public int EncodeBytes(ReadOnlySpan buffer) { throw new NotImplementedException(); } public int EncodeString(string value, Encoding encoding) { throw new NotImplementedException(); } diff --git a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/IByteEncoder.cs b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/IByteEncoder.cs index 33af3546eeb..4fe429f3c59 100644 --- a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/IByteEncoder.cs +++ b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/IByteEncoder.cs @@ -8,7 +8,7 @@ namespace System.Net.Mime internal interface IByteEncoder { // This method does not account for codepoint boundaries. If encoding a string, consider using EncodeString - int EncodeBytes(byte[] buffer, int offset, int count, bool dontDeferFinalBytes, bool shouldAppendSpaceToCRLF); + int EncodeBytes(ReadOnlySpan buffer, bool dontDeferFinalBytes, bool shouldAppendSpaceToCRLF); void AppendPadding(); int EncodeString(string value, Encoding encoding); string GetEncodedString(); diff --git a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/IEncodableStream.cs b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/IEncodableStream.cs index 43bd90210af..6a1122f8845 100644 --- a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/IEncodableStream.cs +++ b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/IEncodableStream.cs @@ -7,9 +7,9 @@ namespace System.Net.Mime { internal interface IEncodableStream { - int DecodeBytes(byte[] buffer, int offset, int count); + int DecodeBytes(Span buffer); // This method does not account for codepoint boundaries. If encoding a string, consider using EncodeString - int EncodeBytes(byte[] buffer, int offset, int count); + int EncodeBytes(ReadOnlySpan buffer); int EncodeString(string value, Encoding encoding); string GetEncodedString(); } diff --git a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/MimeBasePart.cs b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/MimeBasePart.cs index 332f9db055e..804c067eb20 100644 --- a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/MimeBasePart.cs +++ b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/MimeBasePart.cs @@ -76,7 +76,7 @@ internal static string DecodeHeaderValue(string? value) IEncodableStream s = EncodedStreamFactory.GetEncoderForHeader(Encoding.GetEncoding(charSet), base64Encoding, 0); - newLength = s.DecodeBytes(buffer, 0, buffer.Length); + newLength = s.DecodeBytes(buffer); Encoding encoding = Encoding.GetEncoding(charSet); newValue += encoding.GetString(buffer, 0, newLength); diff --git a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/QEncodedStream.cs b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/QEncodedStream.cs index 47d3026e6aa..cafb9b0577e 100644 --- a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/QEncodedStream.cs +++ b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/QEncodedStream.cs @@ -5,6 +5,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using System.Buffers; namespace System.Net.Mime { @@ -52,8 +53,8 @@ internal QEncodedStream(WriteStateInfoBase wsi) : base(new MemoryStream()) internal WriteStateInfoBase WriteState => _writeState; - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) => - TaskToAsyncResult.Begin(WriteAsync(buffer, offset, count, CancellationToken.None), callback, state); + public override bool CanRead => BaseStream.CanRead; + public override bool CanWrite => BaseStream.CanWrite; public override void Close() { @@ -61,14 +62,14 @@ public override void Close() base.Close(); } - public unsafe int DecodeBytes(byte[] buffer, int offset, int count) + public unsafe int DecodeBytes(Span buffer) { fixed (byte* pBuffer = buffer) { - byte* start = pBuffer + offset; + byte* start = pBuffer; byte* source = start; byte* dest = start; - byte* end = start + count; + byte* end = start + buffer.Length; // if the last read ended in a partially decoded // sequence, pick up where we left off. @@ -81,7 +82,7 @@ public unsafe int DecodeBytes(byte[] buffer, int offset, int count) // if we only read one byte from the underlying // stream, we'll need to save the byte and // ask for more. - if (count == 1) + if (buffer.Length == 1) { ReadState.Byte = *source; return 0; @@ -179,15 +180,12 @@ public unsafe int DecodeBytes(byte[] buffer, int offset, int count) } } - public int EncodeBytes(byte[] buffer, int offset, int count) => _encoder.EncodeBytes(buffer, offset, count, true, true); + public int EncodeBytes(ReadOnlySpan buffer) => _encoder.EncodeBytes(buffer, true, true); public int EncodeString(string value, Encoding encoding) => _encoder.EncodeString(value, encoding); public string GetEncodedString() => _encoder.GetEncodedString(); - public override void EndWrite(IAsyncResult asyncResult) => - TaskToAsyncResult.End(asyncResult); - public override void Flush() { FlushInternal(); @@ -195,34 +193,46 @@ public override void Flush() } public override async Task FlushAsync(CancellationToken cancellationToken) + { + await FlushInternalAsync(cancellationToken).ConfigureAwait(false); + await base.FlushAsync(cancellationToken).ConfigureAwait(false); + } + + private void FlushInternal() { if (_writeState != null && _writeState.Length > 0) { - await base.WriteAsync(WriteState.Buffer.AsMemory(0, WriteState.Length), cancellationToken).ConfigureAwait(false); + BaseStream.Write(WriteState.Buffer.AsSpan(0, WriteState.Length)); WriteState.Reset(); } - - await base.FlushAsync(cancellationToken).ConfigureAwait(false); } - private void FlushInternal() + private async ValueTask FlushInternalAsync(CancellationToken cancellationToken) { if (_writeState != null && _writeState.Length > 0) { - base.Write(WriteState.Buffer, 0, WriteState.Length); + await BaseStream.WriteAsync(WriteState.Buffer.AsMemory(0, WriteState.Length), cancellationToken).ConfigureAwait(false); WriteState.Reset(); } } - public override void Write(byte[] buffer, int offset, int count) + protected override int ReadInternal(Span buffer) { - ValidateBufferArguments(buffer, offset, count); + throw new NotImplementedException(); + } + protected override ValueTask ReadAsyncInternal(Memory buffer, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + protected override void WriteInternal(ReadOnlySpan buffer) + { int written = 0; while (true) { - written += EncodeBytes(buffer, offset + written, count - written); - if (written < count) + written += EncodeBytes(buffer.Slice(written)); + if (written < buffer.Length) { FlushInternal(); } @@ -233,31 +243,23 @@ public override void Write(byte[] buffer, int offset, int count) } } - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + protected override async ValueTask WriteAsyncInternal(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) { - ValidateBufferArguments(buffer, offset, count); - return WriteAsyncCore(buffer, offset, count, cancellationToken); - - async Task WriteAsyncCore(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + int written = 0; + while (true) { - int written = 0; - while (true) + written += EncodeBytes(buffer.Span.Slice(written)); + if (written < buffer.Length) { - written += EncodeBytes(buffer, offset + written, count - written); - if (written < count) - { - await FlushAsync(cancellationToken).ConfigureAwait(false); - } - else - { - break; - } + await FlushInternalAsync(cancellationToken).ConfigureAwait(false); + } + else + { + break; } } } - - private sealed class ReadStateInfo { internal bool IsEscaped { get; set; } diff --git a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/QEncoder.cs b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/QEncoder.cs index 9ba70456d66..8bf8b7d67fd 100644 --- a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/QEncoder.cs +++ b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/QEncoder.cs @@ -44,14 +44,14 @@ protected override bool LineBreakNeeded(byte b) return false; } - protected override bool LineBreakNeeded(byte[] bytes, int count) + protected override bool LineBreakNeeded(ReadOnlySpan bytes) { - if (count == 1 || IsCRLF(bytes, count)) // preserve same behavior as in EncodeBytes + if (bytes.Length == 1 || IsCRLF(bytes)) // preserve same behavior as in EncodeBytes { return LineBreakNeeded(bytes[0]); } - int numberOfCharsToAppend = count * SizeOfQEncodedChar; + int numberOfCharsToAppend = bytes.Length * SizeOfQEncodedChar; return WriteState.CurrentLineLength + numberOfCharsToAppend + _writeState.FooterLength > WriteState.MaxLineLength; } @@ -74,7 +74,7 @@ protected override int GetCodepointSize(string value, int i) // no padding in q-encoding public override void AppendPadding() { } - protected override void ApppendEncodedByte(byte b) + protected override void AppendEncodedByte(byte b) { if (b == ' ') { diff --git a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/QuotedPrintableStream.cs b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/QuotedPrintableStream.cs index 6440ea0d7cc..773e12b430f 100644 --- a/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/QuotedPrintableStream.cs +++ b/src/runtime/src/libraries/System.Net.Mail/src/System/Net/Mime/QuotedPrintableStream.cs @@ -78,27 +78,27 @@ internal QuotedPrintableStream(Stream stream, bool encodeCRLF) : this(stream, En _encodeCRLF = encodeCRLF; } + public override bool CanRead => false; + public override bool CanWrite => BaseStream.CanWrite; + private ReadStateInfo ReadState => _readState ??= new ReadStateInfo(); internal WriteStateInfoBase WriteState => _writeState ??= new WriteStateInfoBase(1024, null, null, _lineLength); - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) => - TaskToAsyncResult.Begin(WriteAsync(buffer, offset, count, CancellationToken.None), callback, state); - public override void Close() { FlushInternal(); base.Close(); } - public unsafe int DecodeBytes(byte[] buffer, int offset, int count) + public unsafe int DecodeBytes(Span buffer) { fixed (byte* pBuffer = buffer) { - byte* start = pBuffer + offset; + byte* start = pBuffer; byte* source = start; byte* dest = start; - byte* end = start + count; + byte* end = start + buffer.Length; // if the last read ended in a partially decoded // sequence, pick up where we left off. @@ -111,7 +111,7 @@ public unsafe int DecodeBytes(byte[] buffer, int offset, int count) // if we only read one byte from the underlying // stream, we'll need to save the byte and // ask for more. - if (count == 1) + if (buffer.Length == 1) { ReadState.Byte = *source; return 0; @@ -201,20 +201,20 @@ public unsafe int DecodeBytes(byte[] buffer, int offset, int count) } } - public int EncodeBytes(byte[] buffer, int offset, int count) + public int EncodeBytes(ReadOnlySpan buffer) { - int cur = offset; - for (; cur < count + offset; cur++) + int processed = 0; + for (; processed < buffer.Length; processed++) { //only fold if we're before a whitespace or if we're at the line limit //add two to the encoded Byte Length to be conservative so that we guarantee that the line length is acceptable - if ((_lineLength != -1 && WriteState.CurrentLineLength + SizeOfEncodedChar + 2 >= _lineLength && (buffer[cur] == ' ' || - buffer[cur] == '\t' || buffer[cur] == '\r' || buffer[cur] == '\n')) || + if ((_lineLength != -1 && WriteState.CurrentLineLength + SizeOfEncodedChar + 2 >= _lineLength && (buffer[processed] == ' ' || + buffer[processed] == '\t' || buffer[processed] == '\r' || buffer[processed] == '\n')) || _writeState!.CurrentLineLength + SizeOfEncodedChar + 2 >= EncodedStreamFactory.DefaultMaxLineLength) { if (WriteState.Buffer.Length - WriteState.Length < SizeOfSoftCRLF) { - return cur - offset; //ok because folding happens externally + return processed; //ok because folding happens externally } WriteState.Append((byte)'='); @@ -225,13 +225,13 @@ public int EncodeBytes(byte[] buffer, int offset, int count) // it is done by the underlying 7BitStream //detect a CRLF in the input and encode it. - if (buffer[cur] == '\r' && cur + 1 < count + offset && buffer[cur + 1] == '\n') + if (buffer[processed] == '\r' && processed + 1 < buffer.Length && buffer[processed + 1] == '\n') { if (WriteState.Buffer.Length - WriteState.Length < (_encodeCRLF ? SizeOfEncodedCRLF : SizeOfNonEncodedCRLF)) { - return cur - offset; + return processed; } - cur++; + processed++; if (_encodeCRLF) { @@ -244,65 +244,62 @@ public int EncodeBytes(byte[] buffer, int offset, int count) } } //ascii chars less than 32 (control chars) and greater than 126 (non-ascii) are not allowed so we have to encode - else if ((buffer[cur] < 32 && buffer[cur] != '\t') || - buffer[cur] == '=' || - buffer[cur] > 126) + else if ((buffer[processed] < 32 && buffer[processed] != '\t') || + buffer[processed] == '=' || + buffer[processed] > 126) { if (WriteState.Buffer.Length - WriteState.Length < SizeOfSoftCRLF) { - return cur - offset; + return processed; } //append an = to indicate an encoded character WriteState.Append((byte)'='); //shift 4 to get the first four bytes only and look up the hex digit - WriteState.Append(HexEncodeMap[buffer[cur] >> 4]); + WriteState.Append(HexEncodeMap[buffer[processed] >> 4]); //clear the first four bytes to get the last four and look up the hex digit - WriteState.Append(HexEncodeMap[buffer[cur] & 0xF]); + WriteState.Append(HexEncodeMap[buffer[processed] & 0xF]); } else { if (WriteState.Buffer.Length - WriteState.Length < 1) { - return cur - offset; + return processed; } //detect special case: is whitespace at end of line? we must encode it if it is - if ((buffer[cur] == (byte)'\t' || buffer[cur] == (byte)' ') && - (cur + 1 >= count + offset)) + if ((buffer[processed] == (byte)'\t' || buffer[processed] == (byte)' ') && + (processed + 1 >= buffer.Length)) { if (WriteState.Buffer.Length - WriteState.Length < SizeOfEncodedChar) { - return cur - offset; + return processed; } //append an = to indicate an encoded character WriteState.Append((byte)'='); //shift 4 to get the first four bytes only and look up the hex digit - WriteState.Append(HexEncodeMap[buffer[cur] >> 4]); + WriteState.Append(HexEncodeMap[buffer[processed] >> 4]); //clear the first four bytes to get the last four and look up the hex digit - WriteState.Append(HexEncodeMap[buffer[cur] & 0xF]); + WriteState.Append(HexEncodeMap[buffer[processed] & 0xF]); } else { - WriteState.Append(buffer[cur]); + WriteState.Append(buffer[processed]); } } } - return cur - offset; + return processed; } public int EncodeString(string value, Encoding encoding) { byte[] buffer = encoding.GetBytes(value); - return EncodeBytes(buffer, 0, buffer.Length); + return EncodeBytes(buffer); } public string GetEncodedString() => Encoding.ASCII.GetString(WriteState.Buffer, 0, WriteState.Length); - public override void EndWrite(IAsyncResult asyncResult) => - TaskToAsyncResult.End(asyncResult); - public override void Flush() { FlushInternal(); @@ -310,34 +307,46 @@ public override void Flush() } public override async Task FlushAsync(CancellationToken cancellationToken) + { + await FlushInternalAsync(cancellationToken).ConfigureAwait(false); + await base.FlushAsync(cancellationToken).ConfigureAwait(false); + } + + private async ValueTask FlushInternalAsync(CancellationToken cancellationToken) { if (_writeState != null && _writeState.Length > 0) { - await base.WriteAsync(WriteState.Buffer.AsMemory(0, WriteState.Length), cancellationToken).ConfigureAwait(false); + await BaseStream.WriteAsync(WriteState.Buffer.AsMemory(0, WriteState.Length), cancellationToken).ConfigureAwait(false); WriteState.BufferFlushed(); } - - await base.FlushAsync(cancellationToken).ConfigureAwait(false); } private void FlushInternal() { if (_writeState != null && _writeState.Length > 0) { - base.Write(WriteState.Buffer, 0, WriteState.Length); + BaseStream.Write(WriteState.Buffer, 0, WriteState.Length); WriteState.BufferFlushed(); } } - public override void Write(byte[] buffer, int offset, int count) + protected override int ReadInternal(Span buffer) { - ValidateBufferArguments(buffer, offset, count); + throw new NotImplementedException(); + } + protected override ValueTask ReadAsyncInternal(Memory buffer, CancellationToken cancellationToken = default) + { + throw new NotImplementedException(); + } + + protected override void WriteInternal(ReadOnlySpan buffer) + { int written = 0; while (true) { - written += EncodeBytes(buffer, offset + written, count - written); - if (written < count) + written += EncodeBytes(buffer.Slice(written)); + if (written < buffer.Length) { FlushInternal(); } @@ -348,30 +357,23 @@ public override void Write(byte[] buffer, int offset, int count) } } - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + protected override async ValueTask WriteAsyncInternal(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) { - ValidateBufferArguments(buffer, offset, count); - return WriteAsyncCore(buffer, offset, count, cancellationToken); - - async Task WriteAsyncCore(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + int written = 0; + while (true) { - int written = 0; - while (true) + written += EncodeBytes(buffer.Span.Slice(written)); + if (written < buffer.Length) { - written += EncodeBytes(buffer, offset + written, count - written); - if (written < count) - { - await FlushAsync(cancellationToken).ConfigureAwait(false); - } - else - { - break; - } + await FlushInternalAsync(cancellationToken).ConfigureAwait(false); + } + else + { + break; } } } - private sealed class ReadStateInfo { internal bool IsEscaped { get; set; } diff --git a/src/runtime/src/libraries/System.Net.Mail/tests/Unit/Base64EncodingTest.cs b/src/runtime/src/libraries/System.Net.Mail/tests/Unit/Base64EncodingTest.cs index d441cb2bbc9..926ded2cabb 100644 --- a/src/runtime/src/libraries/System.Net.Mail/tests/Unit/Base64EncodingTest.cs +++ b/src/runtime/src/libraries/System.Net.Mail/tests/Unit/Base64EncodingTest.cs @@ -15,7 +15,7 @@ public void Base64Stream_WithBasicAsciiString_ShouldEncodeAndDecode(string testH { var s = new Base64Stream(new Base64WriteStateInfo()); var testHeaderBytes = Encoding.UTF8.GetBytes(testHeader); - s.EncodeBytes(testHeaderBytes, 0, testHeaderBytes.Length); + s.EncodeBytes(testHeaderBytes); string encodedString = s.GetEncodedString(); for (int i = 0; i < encodedString.Length; i++) @@ -24,7 +24,7 @@ public void Base64Stream_WithBasicAsciiString_ShouldEncodeAndDecode(string testH } byte[] stringToDecode = Encoding.ASCII.GetBytes(encodedString); - int result = s.DecodeBytes(stringToDecode, 0, encodedString.Length); + int result = s.DecodeBytes(stringToDecode.AsSpan(0, encodedString.Length)); Assert.Equal(testHeader, Encoding.UTF8.GetString(stringToDecode, 0, result)); } @@ -43,7 +43,7 @@ public void Base64Stream_EncodeString_WithBasicAsciiString_ShouldEncodeAndDecode } byte[] stringToDecode = Encoding.ASCII.GetBytes(encodedString); - int result = s.DecodeBytes(stringToDecode, 0, encodedString.Length); + int result = s.DecodeBytes(stringToDecode.AsSpan(0, encodedString.Length)); Assert.Equal(testHeader, Encoding.UTF8.GetString(stringToDecode, 0, result)); } @@ -55,13 +55,13 @@ public void Base64Stream_WithVerySmallBuffer_ShouldTriggerBufferResize_AndShould const string TestString = "0123456789abcdef"; byte[] buffer = Encoding.UTF8.GetBytes(TestString); - s.EncodeBytes(buffer, 0, buffer.Length); + s.EncodeBytes(buffer); string encodedString = s.GetEncodedString(); Assert.Equal("MDEyMzQ1Njc4OWFiY2RlZg==", encodedString); byte[] stringToDecode = Encoding.ASCII.GetBytes(encodedString); - int result = s.DecodeBytes(stringToDecode, 0, encodedString.Length); + int result = s.DecodeBytes(stringToDecode.AsSpan(0, encodedString.Length)); Assert.Equal(TestString, Encoding.UTF8.GetString(stringToDecode, 0, result)); } @@ -79,7 +79,7 @@ public void Base64Stream_EncodeString_WithVerySmallBuffer_ShouldTriggerBufferRes Assert.Equal("MDEyMzQ1Njc4OWFiY2RlZg==", encodedString); byte[] stringToDecode = Encoding.ASCII.GetBytes(encodedString); - int result = s.DecodeBytes(stringToDecode, 0, encodedString.Length); + int result = s.DecodeBytes(stringToDecode.AsSpan(0, encodedString.Length)); Assert.Equal(TestString, Encoding.UTF8.GetString(stringToDecode, 0, result)); } @@ -91,11 +91,11 @@ public void Base64Stream_WithVeryLongString_ShouldEncodeProperly() var s = new Base64Stream(writeStateInfo); byte[] buffer = Encoding.UTF8.GetBytes(LongString); - s.EncodeBytes(buffer, 0, buffer.Length); + s.EncodeBytes(buffer); string encodedString = s.GetEncodedString(); byte[] stringToDecode = Encoding.ASCII.GetBytes(encodedString); - int result = s.DecodeBytes(stringToDecode, 0, encodedString.Length); + int result = s.DecodeBytes(stringToDecode.AsSpan(0, encodedString.Length)); Assert.Equal(LongString, Encoding.UTF8.GetString(stringToDecode, 0, result)); } @@ -110,7 +110,7 @@ public void Base64Stream_EncodeString_WithVeryLongString_ShouldEncodeProperly() string encodedString = s.GetEncodedString(); byte[] stringToDecode = Encoding.ASCII.GetBytes(encodedString); - int result = s.DecodeBytes(stringToDecode, 0, encodedString.Length); + int result = s.DecodeBytes(stringToDecode.AsSpan(0, encodedString.Length)); Assert.Equal(LongString, Encoding.UTF8.GetString(stringToDecode, 0, result)); } diff --git a/src/runtime/src/libraries/System.Net.Mail/tests/Unit/ByteEncodingTest.cs b/src/runtime/src/libraries/System.Net.Mail/tests/Unit/ByteEncodingTest.cs index 37c7e0aefcf..1d0fc9db466 100644 --- a/src/runtime/src/libraries/System.Net.Mail/tests/Unit/ByteEncodingTest.cs +++ b/src/runtime/src/libraries/System.Net.Mail/tests/Unit/ByteEncodingTest.cs @@ -121,7 +121,7 @@ public void EncodeString_IsSameAsEncodeBytes_IfOneByteCodepointOnLineWrap(bool u string encodeStringResult = streamForEncodeString.GetEncodedString(); byte[] bytes = Encoding.UTF8.GetBytes(value); - streamForEncodeBytes.EncodeBytes(bytes, 0, bytes.Length); + streamForEncodeBytes.EncodeBytes(bytes); string encodeBytesResult = streamForEncodeBytes.GetEncodedString(); Assert.Equal(encodeBytesResult, encodeStringResult); diff --git a/src/runtime/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs b/src/runtime/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs index 5160628cf82..1e0a8ed0e2a 100644 --- a/src/runtime/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs +++ b/src/runtime/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs @@ -1056,8 +1056,9 @@ internal bool VerifyRemoteCertificate(RemoteCertificateValidationCallback? remot return true; } - _remoteCertificate = certificate; - if (_remoteCertificate == null) + // don't assign to _remoteCertificate yet, this prevents weird exceptions if SslStream is disposed in parallel with X509Chain building + + if (certificate == null) { if (NetEventSource.Log.IsEnabled() && RemoteCertRequired) NetEventSource.Error(this, $"Remote certificate required, but no remote certificate received"); sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNotAvailable; @@ -1099,15 +1100,17 @@ internal bool VerifyRemoteCertificate(RemoteCertificateValidationCallback? remot sslPolicyErrors |= CertificateValidationPal.VerifyCertificateProperties( _securityContext!, chain, - _remoteCertificate, + certificate, _sslAuthenticationOptions.CheckCertName, _sslAuthenticationOptions.IsServer, TargetHostNameHelper.NormalizeHostName(_sslAuthenticationOptions.TargetHost)); } + _remoteCertificate = certificate; + if (remoteCertValidationCallback != null) { - success = remoteCertValidationCallback(this, _remoteCertificate, chain, sslPolicyErrors); + success = remoteCertValidationCallback(this, certificate, chain, sslPolicyErrors); } else { diff --git a/src/runtime/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.cs b/src/runtime/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.cs index bcf2a5bf88d..7c2897d0e9b 100644 --- a/src/runtime/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.cs +++ b/src/runtime/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.cs @@ -927,7 +927,8 @@ private void ThrowIfExceptionalOrNotHandshake() { ThrowIfExceptional(); - if (!IsAuthenticated) + // if the Protocol is set then rest of the ConnectionInfo is valid + if (_connectionInfo.Protocol == 0) { ThrowNotAuthenticated(); } diff --git a/src/runtime/src/libraries/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs b/src/runtime/src/libraries/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs index e3f11f7e835..acdf3cf160e 100644 --- a/src/runtime/src/libraries/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs +++ b/src/runtime/src/libraries/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs @@ -145,7 +145,7 @@ private async Task ClientAsyncSslHelper( Task clientTask = client.AuthenticateAsClientAsync(new SslClientAuthenticationOptions { EnabledSslProtocols = clientSslProtocols, - RemoteCertificateValidationCallback = AllowAnyServerCertificate, + RemoteCertificateValidationCallback = certificateCallback ?? AllowAnyServerCertificate, TargetHost = serverName }); serverTask = server.AuthenticateAsServerAsync(new SslServerAuthenticationOptions diff --git a/src/runtime/src/libraries/System.Numerics.Tensors/src/Resources/Strings.resx b/src/runtime/src/libraries/System.Numerics.Tensors/src/Resources/Strings.resx index 208b9802175..6561dfdafbf 100644 --- a/src/runtime/src/libraries/System.Numerics.Tensors/src/Resources/Strings.resx +++ b/src/runtime/src/libraries/System.Numerics.Tensors/src/Resources/Strings.resx @@ -177,8 +177,8 @@ In place operations require the same shape for both tensors - - Invalid axis provided. Must be greater then or equal to 0 and less than the tensor rank. + + Invalid dimension provided. Must be greater then or equal to 0 and less than the tensor rank. The tensors must have the same shape, except in the dimension corresponding to axis. diff --git a/src/runtime/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Tensor.cs b/src/runtime/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Tensor.cs index aaf9612ae0a..8d4a670a1bd 100644 --- a/src/runtime/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Tensor.cs +++ b/src/runtime/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/Tensor.cs @@ -133,18 +133,14 @@ public static Tensor ConcatenateOnDimension(int dimension, params scoped R ThrowHelper.ThrowArgument_ConcatenateTooFewTensors(); if (dimension < -1 || dimension > tensors[0].Rank) - ThrowHelper.ThrowArgument_InvalidAxis(); + ThrowHelper.ThrowArgument_InvalidDimension(); - // Calculate total space needed. - nint totalLength = 0; - for (int i = 0; i < tensors.Length; i++) - totalLength += tensors[i].FlattenedLength; + Tensor tensor; - nint sumOfAxis = 0; // If axis != -1, make sure all dimensions except the one to concatenate on match. if (dimension != -1) { - sumOfAxis = tensors[0].Lengths[dimension]; + nint sumOfAxis = tensors[0].Lengths[dimension]; for (int i = 1; i < tensors.Length; i++) { if (tensors[0].Rank != tensors[i].Rank) @@ -157,22 +153,31 @@ public static Tensor ConcatenateOnDimension(int dimension, params scoped R ThrowHelper.ThrowArgument_InvalidConcatenateShape(); } } - sumOfAxis += tensors[i].Lengths[dimension]; + checked + { + sumOfAxis += tensors[i].Lengths[dimension]; + } } - } - Tensor tensor; - if (dimension == -1) - { - tensor = Tensor.Create([totalLength]); - } - else - { nint[] lengths = new nint[tensors[0].Rank]; tensors[0].Lengths.CopyTo(lengths); lengths[dimension] = sumOfAxis; tensor = Tensor.Create(lengths); } + else + { + // Calculate total space needed. + nint totalLength = 0; + for (int i = 0; i < tensors.Length; i++) + { + checked + { + totalLength += tensors[i].FlattenedLength; + } + } + + tensor = Tensor.Create([totalLength]); + } ConcatenateOnDimension(dimension, tensors, tensor); return tensor; @@ -201,7 +206,7 @@ public static ref readonly TensorSpan ConcatenateOnDimension(int dimension ThrowHelper.ThrowArgument_ConcatenateTooFewTensors(); if (dimension < -1 || dimension > tensors[0].Rank) - ThrowHelper.ThrowArgument_InvalidAxis(); + ThrowHelper.ThrowArgument_InvalidDimension(); // Calculate total space needed. nint totalLength = 0; @@ -212,11 +217,12 @@ public static ref readonly TensorSpan ConcatenateOnDimension(int dimension if (dimension != -1) { nint sumOfAxis = tensors[0].Lengths[dimension]; + int rank = tensors[0].Rank; for (int i = 1; i < tensors.Length; i++) { - if (tensors[0].Rank != tensors[i].Rank) + if (rank != tensors[i].Rank) ThrowHelper.ThrowArgument_InvalidConcatenateShape(); - for (int j = 0; j < tensors[0].Rank; j++) + for (int j = 0; j < rank; j++) { if (j != dimension) { @@ -228,7 +234,7 @@ public static ref readonly TensorSpan ConcatenateOnDimension(int dimension } // Make sure the destination tensor has the correct shape. - nint[] lengths = new nint[tensors[0].Rank]; + nint[] lengths = new nint[rank]; tensors[0].Lengths.CopyTo(lengths); lengths[dimension] = sumOfAxis; @@ -339,10 +345,10 @@ public static Tensor Create(T[] array, int start, scoped ReadOnlySpanA new tensor that contains elements copied from . public static Tensor Create(IEnumerable enumerable, bool pinned = false) { + T[] array = enumerable.ToArray(); + if (pinned) { - T[] array = enumerable.ToArray(); - Tensor tensor = CreateUninitialized([array.Length], pinned); array.CopyTo(tensor._values); @@ -350,7 +356,6 @@ public static Tensor Create(IEnumerable enumerable, bool pinned = false } else { - T[] array = enumerable.ToArray(); return Create(array); } } @@ -364,10 +369,10 @@ public static Tensor Create(IEnumerable enumerable, scoped ReadOnlySpan /// A new tensor that contains elements copied from and with the specified and . public static Tensor Create(IEnumerable enumerable, scoped ReadOnlySpan lengths, scoped ReadOnlySpan strides, bool pinned = false) { + T[] array = enumerable.ToArray(); + if (pinned) { - T[] array = enumerable.ToArray(); - Tensor tensor = CreateUninitialized(lengths, strides, pinned); array.CopyTo(tensor._values); @@ -375,7 +380,6 @@ public static Tensor Create(IEnumerable enumerable, scoped ReadOnlySpan } else { - T[] array = enumerable.ToArray(); return Create(array, lengths, strides); } } @@ -620,20 +624,8 @@ public static bool EqualsAny(in ReadOnlyTensorSpan x, T y) /// Value to update in the . public static ref readonly TensorSpan FilteredUpdate(in this TensorSpan tensor, scoped in ReadOnlyTensorSpan filter, T value) { - if (filter.Lengths.Length != tensor.Lengths.Length) - ThrowHelper.ThrowArgument_DimensionsNotSame(nameof(filter)); - - Span srcSpan = MemoryMarshal.CreateSpan(ref tensor._reference, (int)tensor._shape.LinearLength); - Span filterSpan = MemoryMarshal.CreateSpan(ref filter._reference, (int)tensor._shape.LinearLength); - - for (int i = 0; i < filterSpan.Length; i++) - { - if (filterSpan[i]) - { - srcSpan[i] = value; - } - } - + TensorOperation.ValidateCompatibility(filter, tensor); + TensorOperation.Invoke, bool, T, T>(filter, value, tensor); return ref tensor; } @@ -646,24 +638,8 @@ public static ref readonly TensorSpan FilteredUpdate(in this TensorSpan /// Values to update in the . public static ref readonly TensorSpan FilteredUpdate(in this TensorSpan tensor, scoped in ReadOnlyTensorSpan filter, scoped in ReadOnlyTensorSpan values) { - if (filter.Lengths.Length != tensor.Lengths.Length) - ThrowHelper.ThrowArgument_DimensionsNotSame(nameof(filter)); - if (values.Rank != 1) - ThrowHelper.ThrowArgument_1DTensorRequired(nameof(values)); - - Span dstSpan = MemoryMarshal.CreateSpan(ref tensor._reference, (int)tensor._shape.LinearLength); - Span filterSpan = MemoryMarshal.CreateSpan(ref filter._reference, (int)tensor._shape.LinearLength); - Span valuesSpan = MemoryMarshal.CreateSpan(ref values._reference, (int)values._shape.LinearLength); - - int index = 0; - for (int i = 0; i < filterSpan.Length; i++) - { - if (filterSpan[i]) - { - dstSpan[i] = valuesSpan[index++]; - } - } - + TensorOperation.ValidateCompatibility(filter, values, tensor); + TensorOperation.Invoke, bool, T, T>(filter, values, tensor); return ref tensor; } #endregion @@ -1409,6 +1385,9 @@ public static Tensor PermuteDimensions(this Tensor tensor, ReadOnlySpan } else { + if (!dimensions.IsEmpty && dimensions.Length != tensor.Lengths.Length) + ThrowHelper.ThrowArgument_PermuteAxisOrder(); + scoped Span newLengths = TensorOperation.RentedBuffer.CreateUninitialized(tensor.Rank, out TensorOperation.RentedBuffer lengthsRentedBuffer); scoped Span newStrides = TensorOperation.RentedBuffer.CreateUninitialized(tensor.Rank, out TensorOperation.RentedBuffer stridesRentedBuffer); scoped Span newLinearOrder = TensorOperation.RentedBuffer.CreateUninitialized(tensor.Rank, out TensorOperation.RentedBuffer linearOrderRentedBuffer); @@ -1426,11 +1405,12 @@ public static Tensor PermuteDimensions(this Tensor tensor, ReadOnlySpan } else { - if (dimensions.Length != tensor.Lengths.Length) - ThrowHelper.ThrowArgument_PermuteAxisOrder(); - for (int i = 0; i < dimensions.Length; i++) { + if (dimensions[i] >= tensor.Lengths.Length || dimensions[i] < 0) + { + ThrowHelper.ThrowArgument_InvalidDimension(); + } newLengths[i] = tensor.Lengths[dimensions[i]]; newStrides[i] = tensor.Strides[dimensions[i]]; newLinearOrder[i] = tensor._shape.LinearRankOrder[dimensions[i]]; @@ -1467,7 +1447,8 @@ public static Tensor Reshape(this Tensor tensor, ReadOnlySpan len nint[] newLengths = lengths.ToArray(); // Calculate wildcard info. - if (lengths.Contains(-1)) + int wildcardIndex = lengths.IndexOf(-1); + if (wildcardIndex >= 0) { if (lengths.Count(-1) > 1) ThrowHelper.ThrowArgument_OnlyOneWildcard(); @@ -1479,7 +1460,7 @@ public static Tensor Reshape(this Tensor tensor, ReadOnlySpan len tempTotal /= lengths[i]; } } - newLengths[lengths.IndexOf(-1)] = tempTotal; + newLengths[wildcardIndex] = tempTotal; } nint tempLinear = TensorPrimitives.Product(newLengths); @@ -1538,8 +1519,8 @@ public static TensorSpan Reshape(in this TensorSpan tensor, scoped Read } nint[] newLengths = lengths.ToArray(); - // Calculate wildcard info. - if (lengths.Contains(-1)) + int wildcardIndex = lengths.IndexOf(-1); + if (wildcardIndex >= 0) { if (lengths.Count(-1) > 1) ThrowHelper.ThrowArgument_OnlyOneWildcard(); @@ -1551,7 +1532,7 @@ public static TensorSpan Reshape(in this TensorSpan tensor, scoped Read tempTotal /= lengths[i]; } } - newLengths[lengths.IndexOf(-1)] = tempTotal; + newLengths[wildcardIndex] = tempTotal; } @@ -1615,7 +1596,8 @@ public static ReadOnlyTensorSpan Reshape(in this ReadOnlyTensorSpan ten nint[] newLengths = lengths.ToArray(); // Calculate wildcard info. - if (lengths.Contains(-1)) + int wildcardIndex = lengths.IndexOf(-1); + if (wildcardIndex >= 0) { if (lengths.Count(-1) > 1) ThrowHelper.ThrowArgument_OnlyOneWildcard(); @@ -1627,7 +1609,7 @@ public static ReadOnlyTensorSpan Reshape(in this ReadOnlyTensorSpan ten tempTotal /= lengths[i]; } } - newLengths[lengths.IndexOf(-1)] = tempTotal; + newLengths[wildcardIndex] = tempTotal; } @@ -1701,12 +1683,7 @@ public static Tensor Resize(Tensor tensor, ReadOnlySpan lengths) /// Destination with the desired new shape. public static void ResizeTo(scoped in Tensor tensor, in TensorSpan destination) { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref Unsafe.Add(ref tensor.AsTensorSpan()._reference, tensor._start), (int)tensor._values.Length - tensor._start); - Span ospan = MemoryMarshal.CreateSpan(ref destination._reference, (int)destination._shape.LinearLength); - if (ospan.Length >= span.Length) - span.CopyTo(ospan); - else - span.Slice(0, ospan.Length).CopyTo(ospan); + ResizeTo(tensor.AsReadOnlyTensorSpan(), destination); } /// @@ -1717,12 +1694,7 @@ public static void ResizeTo(scoped in Tensor tensor, in TensorSpan dest /// Destination with the desired new shape. public static void ResizeTo(scoped in TensorSpan tensor, in TensorSpan destination) { - ReadOnlySpan span = MemoryMarshal.CreateSpan(ref tensor._reference, (int)tensor._shape.LinearLength); - Span ospan = MemoryMarshal.CreateSpan(ref destination._reference, (int)destination._shape.LinearLength); - if (ospan.Length >= span.Length) - span.CopyTo(ospan); - else - span.Slice(0, ospan.Length).CopyTo(ospan); + ResizeTo(tensor.AsReadOnlyTensorSpan(), destination); } /// @@ -1890,6 +1862,8 @@ public static ref readonly TensorSpan SetSlice(this in TensorSpan tenso /// The axis to split on. public static Tensor[] Split(scoped in ReadOnlyTensorSpan tensor, int splitCount, nint dimension) { + if (dimension < 0 || dimension >= tensor.Rank) + ThrowHelper.ThrowArgument_AxisLargerThanRank(); if (tensor.Lengths[(int)dimension] % splitCount != 0) ThrowHelper.ThrowArgument_SplitNotSplitEvenly(); @@ -2221,8 +2195,10 @@ public static Tensor StackAlongDimension(int dimension, params ReadOnlySpa ThrowHelper.ThrowArgument_StackShapesNotSame(); } - if (dimension < 0) - dimension = tensors[0].Rank - dimension; + // We are safe to do dimension > tensors[0].Rank instead of >= because we are adding a new dimension + // with our call to Unsqueeze. + if (dimension < 0 || dimension > tensors[0].Rank) + ThrowHelper.ThrowArgument_AxisLargerThanRank(); Tensor[] outputs = new Tensor[tensors.Length]; for (int i = 0; i < tensors.Length; i++) @@ -2259,8 +2235,10 @@ public static ref readonly TensorSpan StackAlongDimension(scoped ReadOnlyS ThrowHelper.ThrowArgument_StackShapesNotSame(); } - if (dimension < 0) - dimension = tensors[0].Rank - dimension; + // We are safe to do dimension > tensors[0].Rank instead of >= because we are adding a new dimension + // with our call to Unsqueeze. + if (dimension < 0 || dimension > tensors[0].Rank) + ThrowHelper.ThrowArgument_AxisLargerThanRank(); Tensor[] outputs = new Tensor[tensors.Length]; for (int i = 0; i < tensors.Length; i++) diff --git a/src/runtime/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorOperation.cs b/src/runtime/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorOperation.cs index d372602f2fa..d3b702d050c 100644 --- a/src/runtime/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorOperation.cs +++ b/src/runtime/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorOperation.cs @@ -191,8 +191,8 @@ ref destination xRentedBuffer.Dispose(); } - public static void Invoke(in ReadOnlyTensorSpan x, in ReadOnlyTensorSpan y, in TensorSpan destination) - where TOperation : TensorOperation.IBinaryOperation_Tensor_Tensor + public static void Invoke(in ReadOnlyTensorSpan x, in ReadOnlyTensorSpan y, in TensorSpan destination) + where TOperation : TensorOperation.IBinaryOperation_Tensor_Tensor { scoped Span xIndexes = RentedBuffer.Create(destination.Rank, x.Strides, out nint xLinearOffset, out RentedBuffer xRentedBuffer); scoped Span yIndexes = RentedBuffer.Create(destination.Rank, y.Strides, out nint yLinearOffset, out RentedBuffer yRentedBuffer); @@ -216,6 +216,10 @@ ref Unsafe.Add(ref destination._reference, destinationLinearOffset) destinationRentedBuffer.Dispose(); } + public static void Invoke(in ReadOnlyTensorSpan x, in ReadOnlyTensorSpan y, in TensorSpan destination) + where TOperation : TensorOperation.IBinaryOperation_Tensor_Tensor + => Invoke(in x, in y, in destination); + public static void Invoke(in ReadOnlyTensorSpan x, in ReadOnlyTensorSpan y, ref TResult result) where TOperation : TensorOperation.IBinaryOperation_Tensor_Tensor { @@ -248,8 +252,8 @@ public static void Invoke(in ReadOnlyTensorSpan public static void Invoke(in ReadOnlyTensorSpan x, int y, in TensorSpan destination) where TOperation : TensorOperation.IBinaryOperation_Tensor_Int32 => Invoke(in x, y, in destination); - public static void Invoke(in ReadOnlyTensorSpan x, T2 y, in TensorSpan destination) - where TOperation : TensorOperation.IBinaryOperation_Tensor_Scalar + public static void Invoke(in ReadOnlyTensorSpan x, TArg2 y, in TensorSpan destination) + where TOperation : TensorOperation.IBinaryOperation_Tensor_Scalar { scoped Span xIndexes = RentedBuffer.Create(destination.Rank, x.Strides, out nint xLinearOffset, out RentedBuffer xRentedBuffer); scoped Span destinationIndexes = RentedBuffer.Create(destination.Rank, destination.Strides, out nint destinationLinearOffset, out RentedBuffer destinationRentedBuffer); @@ -292,8 +296,8 @@ ref Unsafe.Add(ref destination._reference, destinationLinearOffset) destinationRentedBuffer.Dispose(); } - public static void Invoke(in ReadOnlyTensorSpan x, T2 y, ref TResult result) - where TOperation : TensorOperation.IBinaryOperation_Tensor_Scalar + public static void Invoke(in ReadOnlyTensorSpan x, TArg2 y, ref TResult result) + where TOperation : TensorOperation.IBinaryOperation_Tensor_Scalar { scoped Span xIndexes = RentedBuffer.Create(x.Rank, x.Strides, out nint xLinearOffset, out RentedBuffer xRentedBuffer); @@ -335,7 +339,7 @@ public static void ValidateCompatibility(in ReadOnlyTensorSpan(in ReadOnlyTensorSpan x, in ReadOnlyTensorSpan y, in TensorSpan destination) + public static void ValidateCompatibility(in ReadOnlyTensorSpan x, in ReadOnlyTensorSpan y, in TensorSpan destination) { // can do bidirectional validation between x and y, that result can then be broadcast to destination if (TensorShape.AreCompatible(x._shape, y._shape, true)) @@ -2153,6 +2157,48 @@ public static void Invoke(Span destination, T value) } } + public readonly struct FilteredUpdate + : IBinaryOperation_Tensor_Scalar, + IBinaryOperation_Tensor_Tensor + { + public static void Invoke(ref readonly bool x, ref readonly T y, ref T destination) + { + if (x) + { + destination = y; + } + } + public static void Invoke(ReadOnlySpan x, ReadOnlySpan y, Span destination) + { + for (int i = 0; i < x.Length; i++) + { + if (x[i]) + { + destination[i] = y[i]; + } + } + } + + public static void Invoke(ref readonly bool x, T y, ref T destination) + { + if (x) + { + destination = y; + } + } + + public static void Invoke(ReadOnlySpan x, T y, Span destination) + { + for (int i = 0; i < x.Length; i++) + { + if (x[i]) + { + destination[i] = y; + } + } + } + } + public readonly struct GreaterThan : IBinaryOperation_Tensor_Scalar, IBinaryOperation_Tensor_Tensor @@ -2531,10 +2577,15 @@ public interface IBinaryOperation_Scalar_Tensor static abstract void Invoke(T1 x, ReadOnlySpan y, Span destination); } + public interface IBinaryOperation_Tensor_Tensor + { + static abstract void Invoke(ref readonly T1 x, ref readonly T2 y, ref TResult destination); + static abstract void Invoke(ReadOnlySpan x, ReadOnlySpan y, Span destination); + } + public interface IBinaryOperation_Tensor_Tensor + : IBinaryOperation_Tensor_Tensor { - static abstract void Invoke(ref readonly T x, ref readonly T y, ref TResult destination); - static abstract void Invoke(ReadOnlySpan x, ReadOnlySpan y, Span destination); } public interface IOperation diff --git a/src/runtime/src/libraries/System.Numerics.Tensors/src/System/ThrowHelper.cs b/src/runtime/src/libraries/System.Numerics.Tensors/src/System/ThrowHelper.cs index 81338921a58..f19d78077b9 100644 --- a/src/runtime/src/libraries/System.Numerics.Tensors/src/System/ThrowHelper.cs +++ b/src/runtime/src/libraries/System.Numerics.Tensors/src/System/ThrowHelper.cs @@ -197,9 +197,9 @@ public static void ThrowArgument_ConcatenateTooFewTensors() } [DoesNotReturn] - public static void ThrowArgument_InvalidAxis() + public static void ThrowArgument_InvalidDimension() { - throw new ArgumentException(SR.ThrowArgument_InvalidAxis); + throw new ArgumentException(SR.ThrowArgument_InvalidDimension); } [DoesNotReturn] diff --git a/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.Android.cs b/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.Android.cs index ac6278be710..eac704b65bb 100644 --- a/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.Android.cs +++ b/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.Android.cs @@ -2,12 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Internal { public static partial class Console { + [MethodImplAttribute(MethodImplOptions.NoInlining)] public static unsafe void Write(string s) { Interop.Logcat.AndroidLogPrint(Interop.Logcat.LogLevel.Debug, "DOTNET", s ?? string.Empty); @@ -15,6 +17,7 @@ public static unsafe void Write(string s) public static partial class Error { + [MethodImplAttribute(MethodImplOptions.NoInlining)] public static unsafe void Write(string s) { Interop.Logcat.AndroidLogPrint(Interop.Logcat.LogLevel.Error, "DOTNET", s ?? string.Empty); diff --git a/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.Unix.cs b/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.Unix.cs index cea820aae12..805025845ed 100644 --- a/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.Unix.cs +++ b/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.Unix.cs @@ -2,12 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.CompilerServices; using System.Text; namespace Internal { public static partial class Console { + [MethodImplAttribute(MethodImplOptions.NoInlining)] public static unsafe void Write(string s) { byte[] bytes = Encoding.UTF8.GetBytes(s); @@ -19,6 +21,7 @@ public static unsafe void Write(string s) public static partial class Error { + [MethodImplAttribute(MethodImplOptions.NoInlining)] public static unsafe void Write(string s) { byte[] bytes = Encoding.UTF8.GetBytes(s); diff --git a/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.Windows.cs b/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.Windows.cs index 9c0ce4d54d9..ba6dea322c4 100644 --- a/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.Windows.cs +++ b/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.Windows.cs @@ -2,12 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.CompilerServices; using System.Text; namespace Internal { public static partial class Console { + [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void Write(string s) { WriteCore(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_OUTPUT_HANDLE), s); @@ -15,6 +17,7 @@ public static void Write(string s) public static partial class Error { + [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void Write(string s) { WriteCore(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_ERROR_HANDLE), s); diff --git a/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.cs b/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.cs index c6ce19fae3b..6e2629d3559 100644 --- a/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.cs +++ b/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.CompilerServices; namespace Internal { @@ -12,14 +13,17 @@ namespace Internal public static partial class Console { + [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine(string? s) => Write(s + Environment.NewLineConst); + [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine() => Write(Environment.NewLineConst); public static partial class Error { + [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine() => Write(Environment.NewLineConst); } diff --git a/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.iOS.cs b/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.iOS.cs index 84e0bbdcea2..839ef95a081 100644 --- a/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.iOS.cs +++ b/src/runtime/src/libraries/System.Private.CoreLib/src/Internal/Console.iOS.cs @@ -2,12 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.CompilerServices; using System.Text; namespace Internal { public static partial class Console { + [MethodImplAttribute(MethodImplOptions.NoInlining)] public static unsafe void Write(string s) { fixed (char* ptr = s) @@ -17,6 +19,7 @@ public static unsafe void Write(string s) } public static partial class Error { + [MethodImplAttribute(MethodImplOptions.NoInlining)] public static unsafe void Write(string s) { fixed (char* ptr = s) diff --git a/src/runtime/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx10v2.PlatformNotSupported.cs b/src/runtime/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx10v2.PlatformNotSupported.cs index bea42e51167..0ebb9b5ffc1 100644 --- a/src/runtime/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx10v2.PlatformNotSupported.cs +++ b/src/runtime/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx10v2.PlatformNotSupported.cs @@ -119,16 +119,6 @@ internal Avx10v2() { } /// public static Vector256 ConvertToByteWithTruncatedSaturationAndZeroExtendToInt32(Vector256 value) { throw new PlatformNotSupportedException(); } - /// - /// VMOVD xmm1, xmm2/m32 - /// - public static Vector128 ConvertToVector128UInt32(Vector128 value) { throw new PlatformNotSupportedException(); } - - /// - /// VMOVW xmm1, xmm2/m16 - /// - public static Vector128 ConvertToVector128UInt16(Vector128 value) { throw new PlatformNotSupportedException(); } - /// /// VCVTDQ2PS ymm1{k1}{z}, ymm2/m256/m32bcst {er} /// @@ -204,6 +194,26 @@ internal Avx10v2() { } /// public static Vector256 ConvertToVector256Double(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); } + /// + /// VMOVD xmm1, xmm2/m32 + /// + public static Vector128 MoveScalar(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// VMOVD xmm1, xmm2/m32 + /// + public static Vector128 MoveScalar(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// VMOVW xmm1, xmm2/m16 + /// + public static Vector128 MoveScalar(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// VMOVW xmm1, xmm2/m16 + /// + public static Vector128 MoveScalar(Vector128 value) { throw new PlatformNotSupportedException(); } + /// /// VMULPD ymm1{k1}{z}, ymm2, ymm3/m256/m64bcst {er} /// @@ -234,6 +244,16 @@ internal Avx10v2() { } /// public static Vector256 Sqrt(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw new PlatformNotSupportedException(); } + /// + /// VMOVW xmm1/m16, xmm2 + /// + public static unsafe void StoreScalar(short* address, Vector128 source) { throw new PlatformNotSupportedException(); } + + /// + /// VMOVW xmm1/m16, xmm2 + /// + public static unsafe void StoreScalar(ushort* address, Vector128 source) { throw new PlatformNotSupportedException(); } + /// /// VSUBPD ymm1{k1}{z}, ymm2, ymm3/m256/m64bcst {er} /// diff --git a/src/runtime/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx10v2.cs b/src/runtime/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx10v2.cs index 5c9cba0625f..9a1a76511b9 100644 --- a/src/runtime/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx10v2.cs +++ b/src/runtime/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Avx10v2.cs @@ -98,16 +98,6 @@ internal Avx10v2() { } /// public static Vector256 ConvertToByteWithTruncatedSaturationAndZeroExtendToInt32(Vector256 value) => ConvertToByteWithTruncatedSaturationAndZeroExtendToInt32(value); - /// - /// VMOVD xmm1, xmm2/m32 - /// - public static Vector128 ConvertToVector128UInt32(Vector128 value) => ConvertToVector128UInt32(value); - - /// - /// VMOVW xmm1, xmm2/m16 - /// - public static Vector128 ConvertToVector128UInt16(Vector128 value) => ConvertToVector128UInt16(value); - /// /// VADDPD ymm1{k1}{z}, ymm2, ymm3/m256/m64bcst {er} /// @@ -203,6 +193,26 @@ internal Avx10v2() { } /// public static Vector256 ConvertToVector256Double(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => ConvertToVector256Double(value, mode); + /// + /// VMOVD xmm1, xmm2/m32 + /// + public static Vector128 MoveScalar(Vector128 value) => MoveScalar(value); + + /// + /// VMOVD xmm1, xmm2/m32 + /// + public static Vector128 MoveScalar(Vector128 value) => MoveScalar(value); + + /// + /// VMOVW xmm1, xmm2/m16 + /// + public static Vector128 MoveScalar(Vector128 value) => MoveScalar(value); + + /// + /// VMOVW xmm1, xmm2/m16 + /// + public static Vector128 MoveScalar(Vector128 value) => MoveScalar(value); + /// /// VMULPD ymm1{k1}{z}, ymm2, ymm3/m256/m64bcst {er} /// @@ -233,6 +243,16 @@ internal Avx10v2() { } /// public static Vector256 Sqrt(Vector256 value, [ConstantExpected(Max = FloatRoundingMode.ToZero)] FloatRoundingMode mode) => Sqrt(value, mode); + /// + /// VMOVW xmm1/m16, xmm2 + /// + public static unsafe void StoreScalar(short* address, Vector128 source) => StoreScalar(address, source); + + /// + /// VMOVW xmm1/m16, xmm2 + /// + public static unsafe void StoreScalar(ushort* address, Vector128 source) => StoreScalar(address, source); + /// /// VSUBPD ymm1{k1}{z}, ymm2, ymm3/m256/m64bcst {er} /// diff --git a/src/runtime/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/NativeExports.csproj b/src/runtime/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/NativeExports.csproj index 0b3b2b8317b..2883960c931 100644 --- a/src/runtime/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/NativeExports.csproj +++ b/src/runtime/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/NativeExports.csproj @@ -11,11 +11,6 @@ $(OutputRID) $(OutputRID) - - $(BaseOS) true false @@ -123,6 +118,7 @@ $([System.IO.Path]::GetDirectoryName('$(AppHostSourcePath)')) + + + + $([MSBuild]::NormalizePath('$(BootstrapRidGraphDir)', 'runtime.json')) + + diff --git a/src/runtime/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/runtime/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index fa00f8e560f..bfa28b6b109 100644 --- a/src/runtime/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/runtime/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -7251,8 +7251,6 @@ internal Avx10v2() { } public static System.Runtime.Intrinsics.Vector256 ConvertToSByteWithTruncatedSaturationAndZeroExtendToInt32(System.Runtime.Intrinsics.Vector256 value) { throw null; } public static System.Runtime.Intrinsics.Vector128 ConvertToByteWithTruncatedSaturationAndZeroExtendToInt32(System.Runtime.Intrinsics.Vector128 value) { throw null; } public static System.Runtime.Intrinsics.Vector256 ConvertToByteWithTruncatedSaturationAndZeroExtendToInt32(System.Runtime.Intrinsics.Vector256 value) { throw null; } - public static System.Runtime.Intrinsics.Vector128 ConvertToVector128UInt32(System.Runtime.Intrinsics.Vector128 value) { throw null; } - public static System.Runtime.Intrinsics.Vector128 ConvertToVector128UInt16(System.Runtime.Intrinsics.Vector128 value) { throw null; } public static System.Runtime.Intrinsics.Vector256 ConvertToVector256Single(System.Runtime.Intrinsics.Vector256 value, [System.Diagnostics.CodeAnalysis.ConstantExpected(Max = System.Runtime.Intrinsics.X86.FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw null; } public static System.Runtime.Intrinsics.Vector128 ConvertToVector128Int32(System.Runtime.Intrinsics.Vector256 value, [System.Diagnostics.CodeAnalysis.ConstantExpected(Max = System.Runtime.Intrinsics.X86.FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw null; } public static System.Runtime.Intrinsics.Vector128 ConvertToVector128Single(System.Runtime.Intrinsics.Vector256 value, [System.Diagnostics.CodeAnalysis.ConstantExpected(Max = System.Runtime.Intrinsics.X86.FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw null; } @@ -7268,12 +7266,18 @@ internal Avx10v2() { } public static System.Runtime.Intrinsics.Vector256 ConvertToVector256Single(System.Runtime.Intrinsics.Vector256 value, [System.Diagnostics.CodeAnalysis.ConstantExpected(Max = System.Runtime.Intrinsics.X86.FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw null; } public static System.Runtime.Intrinsics.Vector128 ConvertToVector128Single(System.Runtime.Intrinsics.Vector256 value, [System.Diagnostics.CodeAnalysis.ConstantExpected(Max = System.Runtime.Intrinsics.X86.FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw null; } public static System.Runtime.Intrinsics.Vector256 ConvertToVector256Double(System.Runtime.Intrinsics.Vector256 value, [System.Diagnostics.CodeAnalysis.ConstantExpected(Max = System.Runtime.Intrinsics.X86.FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw null; } + public static System.Runtime.Intrinsics.Vector128 MoveScalar(System.Runtime.Intrinsics.Vector128 value) { throw null; } + public static System.Runtime.Intrinsics.Vector128 MoveScalar(System.Runtime.Intrinsics.Vector128 value) { throw null; } + public static System.Runtime.Intrinsics.Vector128 MoveScalar(System.Runtime.Intrinsics.Vector128 value) { throw null; } + public static System.Runtime.Intrinsics.Vector128 MoveScalar(System.Runtime.Intrinsics.Vector128 value) { throw null; } public static System.Runtime.Intrinsics.Vector256 Multiply(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right, [System.Diagnostics.CodeAnalysis.ConstantExpected(Max = System.Runtime.Intrinsics.X86.FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw null; } public static System.Runtime.Intrinsics.Vector256 Multiply(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right, [System.Diagnostics.CodeAnalysis.ConstantExpected(Max = System.Runtime.Intrinsics.X86.FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw null; } public static System.Runtime.Intrinsics.Vector256 Scale(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right, [System.Diagnostics.CodeAnalysis.ConstantExpected(Max = System.Runtime.Intrinsics.X86.FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw null; } public static System.Runtime.Intrinsics.Vector256 Scale(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right, [System.Diagnostics.CodeAnalysis.ConstantExpected(Max = System.Runtime.Intrinsics.X86.FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw null; } public static System.Runtime.Intrinsics.Vector256 Sqrt(System.Runtime.Intrinsics.Vector256 value, [System.Diagnostics.CodeAnalysis.ConstantExpected(Max = System.Runtime.Intrinsics.X86.FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw null; } public static System.Runtime.Intrinsics.Vector256 Sqrt(System.Runtime.Intrinsics.Vector256 value, [System.Diagnostics.CodeAnalysis.ConstantExpected(Max = System.Runtime.Intrinsics.X86.FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw null; } + public static unsafe void StoreScalar(short* address, System.Runtime.Intrinsics.Vector128 source) { throw null; } + public static unsafe void StoreScalar(ushort* address, System.Runtime.Intrinsics.Vector128 source) { throw null; } public static System.Runtime.Intrinsics.Vector256 Subtract(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right, [System.Diagnostics.CodeAnalysis.ConstantExpected(Max = System.Runtime.Intrinsics.X86.FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw null; } public static System.Runtime.Intrinsics.Vector256 Subtract(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right, [System.Diagnostics.CodeAnalysis.ConstantExpected(Max = System.Runtime.Intrinsics.X86.FloatRoundingMode.ToZero)] FloatRoundingMode mode) { throw null; } diff --git a/src/runtime/src/libraries/System.Runtime/tests/System.Globalization.Tests/CultureInfo/CultureInfoCtor.cs b/src/runtime/src/libraries/System.Runtime/tests/System.Globalization.Tests/CultureInfo/CultureInfoCtor.cs index 8fa5ba6f53a..b06bb08693e 100644 --- a/src/runtime/src/libraries/System.Runtime/tests/System.Globalization.Tests/CultureInfo/CultureInfoCtor.cs +++ b/src/runtime/src/libraries/System.Runtime/tests/System.Globalization.Tests/CultureInfo/CultureInfoCtor.cs @@ -388,11 +388,28 @@ public static IEnumerable Ctor_String_TestData() } } + public static IEnumerable Ctor_Undetermined_TestData() + { + yield return new object[] { "und-us", "und-US", "und-US" }; + yield return new object[] { "und-us_tradnl", "und-US", "und-US_tradnl"}; + + // On AppleMobile, the behavior of CultureInfo differs due to platform-specific + // handling of Unicode extensions and subtags. These platforms preserve the full language tag, including + // extensions, while other platforms normalize the tag to a simpler form. + if (PlatformDetection.IsAppleMobile) + { + yield return new object[] { "und-es-u-co-phoneb", "und-ES-u-co-phoneb", "und-ES-u-co-phoneb" }; + yield return new object[] { "und-es-t-something", "und-ES-t-something", "und-ES-t-something" }; + } + else + { + yield return new object[] { "und-es-u-co-phoneb", "und-ES", "und-ES_phoneb" }; + yield return new object[] { "und-es-t-something", "und-ES", "und-ES"}; + } + } + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalization))] - [InlineData("und-us", "und-US", "und-US")] - [InlineData("und-us_tradnl", "und-US", "und-US_tradnl")] - [InlineData("und-es-u-co-phoneb", "und-ES", "und-ES_phoneb")] - [InlineData("und-es-t-something", "und-ES", "und-ES")] + [MemberData(nameof(Ctor_Undetermined_TestData))] public void CtorUndeterminedLanguageTag(string cultureName, string expectedCultureName, string expectedSortName) { CultureInfo culture = new CultureInfo(cultureName); diff --git a/src/runtime/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs b/src/runtime/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs index f98d464906a..648663322d9 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs @@ -3105,12 +3105,16 @@ public CertificateRequest(System.Security.Cryptography.X509Certificates.X500Dist [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006")] public CertificateRequest(System.Security.Cryptography.X509Certificates.X500DistinguishedName subjectName, System.Security.Cryptography.MLDsa key) { } public CertificateRequest(System.Security.Cryptography.X509Certificates.X500DistinguishedName subjectName, System.Security.Cryptography.RSA key, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.RSASignaturePadding padding) { } + [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006")] + public CertificateRequest(System.Security.Cryptography.X509Certificates.X500DistinguishedName subjectName, System.Security.Cryptography.SlhDsa key) { } public CertificateRequest(System.Security.Cryptography.X509Certificates.X500DistinguishedName subjectName, System.Security.Cryptography.X509Certificates.PublicKey publicKey, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { } public CertificateRequest(System.Security.Cryptography.X509Certificates.X500DistinguishedName subjectName, System.Security.Cryptography.X509Certificates.PublicKey publicKey, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.RSASignaturePadding? rsaSignaturePadding = null) { } public CertificateRequest(string subjectName, System.Security.Cryptography.ECDsa key, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { } [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006")] public CertificateRequest(string subjectName, System.Security.Cryptography.MLDsa key) { } public CertificateRequest(string subjectName, System.Security.Cryptography.RSA key, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.Security.Cryptography.RSASignaturePadding padding) { } + [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006")] + public CertificateRequest(string subjectName, System.Security.Cryptography.SlhDsa key) { } public System.Collections.ObjectModel.Collection CertificateExtensions { get { throw null; } } public System.Security.Cryptography.HashAlgorithmName HashAlgorithm { get { throw null; } } public System.Collections.ObjectModel.Collection OtherRequestAttributes { get { throw null; } } @@ -3212,6 +3216,8 @@ public PublicKey(System.Security.Cryptography.AsymmetricAlgorithm key) { } [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006")] public PublicKey(System.Security.Cryptography.MLKem key) { } public PublicKey(System.Security.Cryptography.Oid oid, System.Security.Cryptography.AsnEncodedData? parameters, System.Security.Cryptography.AsnEncodedData keyValue) { } + [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006")] + public PublicKey(System.Security.Cryptography.SlhDsa key) { } public System.Security.Cryptography.AsnEncodedData EncodedKeyValue { get { throw null; } } public System.Security.Cryptography.AsnEncodedData? EncodedParameters { get { throw null; } } [System.ObsoleteAttribute("PublicKey.Key is obsolete. Use the appropriate method to get the public key, such as GetRSAPublicKey.", DiagnosticId="SYSLIB0027", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] @@ -3235,6 +3241,9 @@ public PublicKey(System.Security.Cryptography.Oid oid, System.Security.Cryptogra public System.Security.Cryptography.MLKem? GetMLKemPublicKey() { throw null; } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public System.Security.Cryptography.RSA? GetRSAPublicKey() { throw null; } + [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] + public System.Security.Cryptography.SlhDsa? GetSlhDsaPublicKey() { throw null; } public bool TryExportSubjectPublicKeyInfo(System.Span destination, out int bytesWritten) { throw null; } } public static partial class RSACertificateExtensions @@ -3548,6 +3557,8 @@ public X509Certificate2(string fileName, string? password, System.Security.Crypt public System.Security.Cryptography.X509Certificates.X509Certificate2 CopyWithPrivateKey(System.Security.Cryptography.MLDsa privateKey) { throw null; } [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006")] public System.Security.Cryptography.X509Certificates.X509Certificate2 CopyWithPrivateKey(System.Security.Cryptography.MLKem privateKey) { throw null; } + [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006")] + public System.Security.Cryptography.X509Certificates.X509Certificate2 CopyWithPrivateKey(System.Security.Cryptography.SlhDsa privateKey) { throw null; } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public static System.Security.Cryptography.X509Certificates.X509Certificate2 CreateFromEncryptedPem(System.ReadOnlySpan certPem, System.ReadOnlySpan keyPem, System.ReadOnlySpan password) { throw null; } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] @@ -3576,6 +3587,10 @@ public X509Certificate2(string fileName, string? password, System.Security.Crypt [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006")] public System.Security.Cryptography.MLKem? GetMLKemPublicKey() { throw null; } public string GetNameInfo(System.Security.Cryptography.X509Certificates.X509NameType nameType, bool forIssuer) { throw null; } + [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006")] + public System.Security.Cryptography.SlhDsa? GetSlhDsaPrivateKey() { throw null; } + [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006")] + public System.Security.Cryptography.SlhDsa? GetSlhDsaPublicKey() { throw null; } [System.ObsoleteAttribute("X509Certificate and X509Certificate2 are immutable. Use X509CertificateLoader to create a new certificate.", DiagnosticId="SYSLIB0026", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] public override void Import(byte[] rawData) { } [System.CLSCompliantAttribute(false)] @@ -3967,6 +3982,8 @@ protected X509SignatureGenerator() { } [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006")] public static System.Security.Cryptography.X509Certificates.X509SignatureGenerator CreateForMLDsa(System.Security.Cryptography.MLDsa key) { throw null; } public static System.Security.Cryptography.X509Certificates.X509SignatureGenerator CreateForRSA(System.Security.Cryptography.RSA key, System.Security.Cryptography.RSASignaturePadding signaturePadding) { throw null; } + [System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SYSLIB5006")] + public static System.Security.Cryptography.X509Certificates.X509SignatureGenerator CreateForSlhDsa(System.Security.Cryptography.SlhDsa key) { throw null; } public abstract byte[] GetSignatureAlgorithmIdentifier(System.Security.Cryptography.HashAlgorithmName hashAlgorithm); public abstract byte[] SignData(byte[] data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm); } diff --git a/src/runtime/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj b/src/runtime/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj index 431ad69cefe..51a71b4218a 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj +++ b/src/runtime/src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj @@ -684,6 +684,7 @@ + diff --git a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/Helpers.cs b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/Helpers.cs index f5dad6061a3..a727674461e 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/Helpers.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/Helpers.cs @@ -465,5 +465,8 @@ internal static void ThrowIfPasswordContainsNullCharacter(string? password) return array; } + + internal static bool IsSlhDsaOid(string? oid) => + SlhDsaAlgorithm.GetAlgorithmFromOid(oid) is not null; } } diff --git a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SlhDsaImplementation.OpenSsl.cs b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SlhDsaImplementation.OpenSsl.cs index c637b957b9f..249cfff2c2a 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SlhDsaImplementation.OpenSsl.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SlhDsaImplementation.OpenSsl.cs @@ -21,6 +21,8 @@ private SlhDsaImplementation(SlhDsaAlgorithm algorithm, SafeEvpPKeyHandle key) _key = key; } + public SafeEvpPKeyHandle DuplicateHandle() => _key.DuplicateHandle(); + internal static partial bool SupportsAny() { bool supportsSlhDsaSha2_128s = Interop.Crypto.EvpPKeySlhDsaAlgs.SlhDsaSha2_128s is not null; @@ -51,7 +53,7 @@ protected override void Dispose(bool disposing) } } - internal static partial SlhDsa GenerateKeyCore(SlhDsaAlgorithm algorithm) + internal static partial SlhDsaImplementation GenerateKeyCore(SlhDsaAlgorithm algorithm) { SafeEvpPKeyHandle key = Interop.Crypto.SlhDsaGenerateKey(algorithm.Name); return new SlhDsaImplementation(algorithm, key); @@ -69,17 +71,17 @@ protected override void ExportSlhDsaPublicKeyCore(Span destination) => protected override void ExportSlhDsaSecretKeyCore(Span destination) => Interop.Crypto.SlhDsaExportSecretKey(_key, destination); - internal static partial SlhDsa ImportPublicKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source) + internal static partial SlhDsaImplementation ImportPublicKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source) { Debug.Assert(source.Length == algorithm.PublicKeySizeInBytes, $"Public key was expected to be {algorithm.PublicKeySizeInBytes} bytes, but was {source.Length} bytes."); SafeEvpPKeyHandle key = Interop.Crypto.EvpPKeyFromData(algorithm.Name, source, privateKey: false); return new SlhDsaImplementation(algorithm, key); } - internal static partial SlhDsa ImportPkcs8PrivateKeyValue(SlhDsaAlgorithm algorithm, ReadOnlySpan source) => + internal static partial SlhDsaImplementation ImportPkcs8PrivateKeyValue(SlhDsaAlgorithm algorithm, ReadOnlySpan source) => throw new PlatformNotSupportedException(); - internal static partial SlhDsa ImportSecretKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source) + internal static partial SlhDsaImplementation ImportSecretKey(SlhDsaAlgorithm algorithm, ReadOnlySpan source) { Debug.Assert(source.Length == algorithm.SecretKeySizeInBytes, $"Secret key was expected to be {algorithm.SecretKeySizeInBytes} bytes, but was {source.Length} bytes."); SafeEvpPKeyHandle key = Interop.Crypto.EvpPKeyFromData(algorithm.Name, source, privateKey: true); diff --git a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/AndroidCertificatePal.cs b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/AndroidCertificatePal.cs index d072e507192..f0192bcb3c9 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/AndroidCertificatePal.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/AndroidCertificatePal.cs @@ -459,6 +459,12 @@ internal SafeKeyHandle? PrivateKeyHandle return null; } + public SlhDsa? GetSlhDsaPrivateKey() + { + // SlhDsa is not supported on Android + return null; + } + public ICertificatePal CopyWithPrivateKey(DSA privateKey) { DSAImplementation.DSAAndroid? typedKey = privateKey as DSAImplementation.DSAAndroid; @@ -521,6 +527,11 @@ public ICertificatePal CopyWithPrivateKey(MLKem privateKey) throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(MLKem))); } + public ICertificatePal CopyWithPrivateKey(SlhDsa privateKey) + { + throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(SlhDsa))); + } + public ICertificatePal CopyWithPrivateKey(RSA privateKey) { RSAImplementation.RSAAndroid? typedKey = privateKey as RSAImplementation.RSAAndroid; diff --git a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/AppleCertificatePal.cs b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/AppleCertificatePal.cs index 7ccfd2386f4..e1ef814155b 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/AppleCertificatePal.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/AppleCertificatePal.cs @@ -381,6 +381,17 @@ public ICertificatePal CopyWithPrivateKey(MLKem privateKey) throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(MLKem))); } + public SlhDsa? GetSlhDsaPrivateKey() + { + // SlhDsa is not supported on Apple platforms. + return null; + } + + public ICertificatePal CopyWithPrivateKey(SlhDsa privateKey) + { + throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(SlhDsa))); + } + public string GetNameInfo(X509NameType nameType, bool forIssuer) { EnsureCertData(); diff --git a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePal.Windows.PrivateKey.cs b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePal.Windows.PrivateKey.cs index 257227bea5a..2e24ea7d636 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePal.Windows.PrivateKey.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePal.Windows.PrivateKey.cs @@ -92,6 +92,12 @@ public bool HasPrivateKey return null; } + public SlhDsa? GetSlhDsaPrivateKey() + { + // SlhDsa is not supported on Windows. + return null; + } + public ICertificatePal CopyWithPrivateKey(DSA dsa) { DSACng? dsaCng = dsa as DSACng; @@ -191,6 +197,11 @@ public ICertificatePal CopyWithPrivateKey(MLKem privateKey) throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(MLKem))); } + public ICertificatePal CopyWithPrivateKey(SlhDsa privateKey) + { + throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_AlgorithmNotSupported, nameof(SlhDsa))); + } + public ICertificatePal CopyWithPrivateKey(RSA rsa) { RSACng? rsaCng = rsa as RSACng; diff --git a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRequest.Load.cs b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRequest.Load.cs index 5893a8ee51b..946a1f28af0 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRequest.Load.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRequest.Load.cs @@ -6,6 +6,7 @@ using System.Formats.Asn1; using System.Security.Cryptography.Asn1; using System.Security.Cryptography.X509Certificates.Asn1; +using Internal.Cryptography; namespace System.Security.Cryptography.X509Certificates { @@ -299,6 +300,7 @@ private static bool VerifyX509Signature( RSA? rsa = publicKey.GetRSAPublicKey(); ECDsa? ecdsa = publicKey.GetECDsaPublicKey(); MLDsa? mldsa = publicKey.GetMLDsaPublicKey(); + SlhDsa? slhDsa = publicKey.GetSlhDsaPublicKey(); try { @@ -348,6 +350,9 @@ private static bool VerifyX509Signature( case Oids.MLDsa87: hashAlg = default; break; + case string oid when Helpers.IsSlhDsaOid(oid): + hashAlg = default; + break; default: throw new NotSupportedException( SR.Format(SR.Cryptography_UnknownKeyAlgorithm, algorithmIdentifier.Algorithm)); @@ -390,6 +395,15 @@ private static bool VerifyX509Signature( } return mldsa.VerifyData(toBeSigned, signature); + + case string oid when Helpers.IsSlhDsaOid(oid): + if (slhDsa is null) + { + return false; + } + + return slhDsa.VerifyData(toBeSigned, signature); + default: Debug.Fail( $"Algorithm ID {algorithmIdentifier.Algorithm} was in the first switch, but not the second"); @@ -409,6 +423,7 @@ private static bool VerifyX509Signature( rsa?.Dispose(); ecdsa?.Dispose(); mldsa?.Dispose(); + slhDsa?.Dispose(); } } } diff --git a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRequest.cs b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRequest.cs index e8e4b34718d..7828dc15d6d 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRequest.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRequest.cs @@ -189,9 +189,9 @@ public CertificateRequest( /// An ML-DSA key whose public key material will be included in the certificate or certificate request. /// This key will be used as a private key if is called. /// - /// + /// /// or is . - /// + /// [Experimental(Experimentals.PostQuantumCryptographyDiagId)] public CertificateRequest( string subjectName, @@ -217,9 +217,9 @@ public CertificateRequest( /// An ML-DSA key whose public key material will be included in the certificate or certificate request. /// This key will be used as a private key if is called. /// - /// + /// /// or is . - /// + /// [Experimental(Experimentals.PostQuantumCryptographyDiagId)] public CertificateRequest( X500DistinguishedName subjectName, @@ -235,6 +235,62 @@ public CertificateRequest( PublicKey = _generator.PublicKey; } + /// + /// Create a CertificateRequest for the specified subject name and SLH-DSA key. + /// + /// + /// The parsed representation of the subject name for the certificate or certificate request. + /// + /// + /// An SLH-DSA key whose public key material will be included in the certificate or certificate request. + /// This key will be used as a private key if is called. + /// + /// + /// or is . + /// + [Experimental(Experimentals.PostQuantumCryptographyDiagId)] + public CertificateRequest( + string subjectName, + SlhDsa key) + { + ArgumentNullException.ThrowIfNull(subjectName); + ArgumentNullException.ThrowIfNull(key); + + SubjectName = new X500DistinguishedName(subjectName); + + _key = key; + _generator = X509SignatureGenerator.CreateForSlhDsa(key); + PublicKey = _generator.PublicKey; + } + + /// + /// Create a CertificateRequest for the specified subject name and SLH-DSA key. + /// + /// + /// The parsed representation of the subject name for the certificate or certificate request. + /// + /// + /// An SLH-DSA key whose public key material will be included in the certificate or certificate request. + /// This key will be used as a private key if is called. + /// + /// + /// or is . + /// + [Experimental(Experimentals.PostQuantumCryptographyDiagId)] + public CertificateRequest( + X500DistinguishedName subjectName, + SlhDsa key) + { + ArgumentNullException.ThrowIfNull(subjectName); + ArgumentNullException.ThrowIfNull(key); + + SubjectName = subjectName; + + _key = key; + _generator = X509SignatureGenerator.CreateForSlhDsa(key); + PublicKey = _generator.PublicKey; + } + /// /// Create a CertificateRequest for the specified subject name, encoded public key, and hash algorithm. /// @@ -591,30 +647,21 @@ public X509Certificate2 CreateSelfSigned(DateTimeOffset notBefore, DateTimeOffse notAfter, serialNumber)) { - RSA? rsa = _key as RSA; - - if (rsa != null) + switch (_key) { - return certificate.CopyWithPrivateKey(rsa); - } - - ECDsa? ecdsa = _key as ECDsa; - - if (ecdsa != null) - { - return certificate.CopyWithPrivateKey(ecdsa); - } - - MLDsa? mldsa = _key as MLDsa; - - if (mldsa is not null) - { - return certificate.CopyWithPrivateKey(mldsa); + case RSA rsa: + return certificate.CopyWithPrivateKey(rsa); + case ECDsa ecdsa: + return certificate.CopyWithPrivateKey(ecdsa); + case MLDsa mldsa: + return certificate.CopyWithPrivateKey(mldsa); + case SlhDsa slhDsa: + return certificate.CopyWithPrivateKey(slhDsa); + default: + Debug.Fail($"Key was of no known type: {_key?.GetType().FullName ?? "null"}"); + throw new CryptographicException(); } } - - Debug.Fail($"Key was of no known type: {_key?.GetType().FullName ?? "null"}"); - throw new CryptographicException(); } /// diff --git a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRevocationListBuilder.Build.cs b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRevocationListBuilder.Build.cs index fe76748c88a..bacec62ca2a 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRevocationListBuilder.Build.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRevocationListBuilder.Build.cs @@ -205,6 +205,11 @@ private byte[] Build( key = mldsa; generator = X509SignatureGenerator.CreateForMLDsa(mldsa!); break; + case string when Helpers.IsSlhDsaOid(keyAlgorithm): + SlhDsa? slhdsa = issuerCertificate.GetSlhDsaPrivateKey(); + key = slhdsa; + generator = X509SignatureGenerator.CreateForSlhDsa(slhdsa!); + break; default: throw new ArgumentException( SR.Format(SR.Cryptography_UnknownKeyAlgorithm, keyAlgorithm), diff --git a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ICertificatePal.cs b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ICertificatePal.cs index 1231bcb4836..9c690a19581 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ICertificatePal.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ICertificatePal.cs @@ -33,6 +33,7 @@ internal interface ICertificatePal : ICertificatePalCore ECDiffieHellman? GetECDiffieHellmanPrivateKey(); MLDsa? GetMLDsaPrivateKey(); MLKem? GetMLKemPrivateKey(); + SlhDsa? GetSlhDsaPrivateKey(); string GetNameInfo(X509NameType nameType, bool forIssuer); void AppendPrivateKeyInfo(StringBuilder sb); ICertificatePal CopyWithPrivateKey(DSA privateKey); @@ -41,6 +42,7 @@ internal interface ICertificatePal : ICertificatePalCore ICertificatePal CopyWithPrivateKey(ECDiffieHellman privateKey); ICertificatePal CopyWithPrivateKey(MLDsa privateKey); ICertificatePal CopyWithPrivateKey(MLKem privateKey); + ICertificatePal CopyWithPrivateKey(SlhDsa privateKey); PolicyData GetPolicyData(); } } diff --git a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslExportProvider.cs b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslExportProvider.cs index 24da35a16c7..5783740ce59 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslExportProvider.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslExportProvider.cs @@ -56,6 +56,14 @@ protected override byte[] ExportPkcs8( } } + if (evpAlgId == Interop.Crypto.EvpAlgorithmFamilyId.SlhDsa) + { + using (SlhDsaOpenSsl slhDsa = new SlhDsaOpenSsl(privateKey)) + { + return slhDsa.ExportEncryptedPkcs8PrivateKey(password, pbeParameters); + } + } + throw new CryptographicException(SR.Cryptography_InvalidHandle); } diff --git a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509CertificateReader.cs b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509CertificateReader.cs index 2cab09b0670..0fa48589caa 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509CertificateReader.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509CertificateReader.cs @@ -628,6 +628,16 @@ public ECDiffieHellman GetECDiffieHellmanPublicKey() return new MLKemOpenSsl(_privateKey); } + public SlhDsa? GetSlhDsaPrivateKey() + { + if (_privateKey == null || _privateKey.IsInvalid) + { + return null; + } + + return new SlhDsaOpenSsl(_privateKey); + } + private OpenSslX509CertificateReader CopyWithPrivateKey(SafeEvpPKeyHandle privateKey) { // This could be X509Duplicate for a full clone, but since OpenSSL certificates @@ -731,6 +741,24 @@ public ICertificatePal CopyWithPrivateKey(MLKem privateKey) } } + public ICertificatePal CopyWithPrivateKey(SlhDsa privateKey) + { + if (privateKey is SlhDsaImplementation impl) + { + return CopyWithPrivateKey(impl.DuplicateHandle()); + } + + if (privateKey is SlhDsaOpenSsl implOpenSsl) + { + return CopyWithPrivateKey(implOpenSsl.DuplicateKeyHandle()); + } + + using (SlhDsaImplementation clone = SlhDsaImplementation.DuplicatePrivateKey(privateKey)) + { + return CopyWithPrivateKey(clone.DuplicateHandle()); + } + } + public ICertificatePal CopyWithPrivateKey(RSA privateKey) { RSAOpenSsl? typedKey = privateKey as RSAOpenSsl; diff --git a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/PublicKey.cs b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/PublicKey.cs index 55176b3bb35..35651a931d1 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/PublicKey.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/PublicKey.cs @@ -62,7 +62,7 @@ public PublicKey(AsymmetricAlgorithm key) : this(key.ExportSubjectPublicKeyInfo( /// using SubjectPublicKeyInfo from an . /// /// - /// An MLKem key to obtain the SubjectPublicKeyInfo from. + /// An key to obtain the SubjectPublicKeyInfo from. /// /// /// The SubjectPublicKeyInfo could not be decoded. The @@ -74,6 +74,23 @@ public PublicKey(MLKem key) : this(key.ExportSubjectPublicKeyInfo()) { } + /// + /// Initializes a new instance of the class + /// using SubjectPublicKeyInfo from an . + /// + /// + /// An key to obtain the SubjectPublicKeyInfo from. + /// + /// + /// The SubjectPublicKeyInfo could not be decoded. The + /// must return a + /// valid ASN.1-DER encoded X.509 SubjectPublicKeyInfo. + /// + [Experimental(Experimentals.PostQuantumCryptographyDiagId)] + public PublicKey(SlhDsa key) : this(key.ExportSubjectPublicKeyInfo()) + { + } + private PublicKey(byte[] subjectPublicKeyInfo) { DecodeSubjectPublicKeyInfo( @@ -340,6 +357,26 @@ public static PublicKey CreateFromSubjectPublicKeyInfo(ReadOnlySpan source return EncodeSubjectPublicKeyInfo().Encode(MLDsa.ImportSubjectPublicKeyInfo); } + /// + /// Gets the public key, or + /// if the key is not an SLH-DSA key. + /// + /// + /// The public key, or if the key is not an SLH-DSA key. + /// + /// + /// The object represents an SLH-DSA public key, but the platform does not support the algorithm. + /// + /// + /// The key contents are corrupt or could not be read successfully. + /// + [Experimental(Experimentals.PostQuantumCryptographyDiagId)] + [UnsupportedOSPlatform("browser")] + public SlhDsa? GetSlhDsaPublicKey() => + Helpers.IsSlhDsaOid(_oid.Value) + ? EncodeSubjectPublicKeyInfo().Encode(SlhDsa.ImportSubjectPublicKeyInfo) + : null; + internal AsnWriter EncodeSubjectPublicKeyInfo() { SubjectPublicKeyInfoAsn spki = new SubjectPublicKeyInfoAsn diff --git a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/SlhDsaX509SignatureGenerator.cs b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/SlhDsaX509SignatureGenerator.cs new file mode 100644 index 00000000000..8eb93631f24 --- /dev/null +++ b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/SlhDsaX509SignatureGenerator.cs @@ -0,0 +1,64 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Formats.Asn1; +using Internal.Cryptography; + +namespace System.Security.Cryptography.X509Certificates +{ + internal sealed class SlhDsaX509SignatureGenerator : X509SignatureGenerator + { + private readonly SlhDsa _key; + + internal SlhDsaX509SignatureGenerator(SlhDsa key) + { + Debug.Assert(key != null); + + _key = key; + } + + public override byte[] GetSignatureAlgorithmIdentifier(HashAlgorithmName hashAlgorithm) + { + // Ignore the hashAlgorithm parameter. + // This generator only supports SLH-DSA "Pure" signatures, but the overall design of + // CertificateRequest makes it easy for a hashAlgorithm value to get here. + + const int InitialCapacity = 16; + + AsnWriter writer = new AsnWriter(AsnEncodingRules.DER, InitialCapacity); + using (writer.PushSequence()) + { + writer.WriteObjectIdentifier(_key.Algorithm.Oid); + } + + Debug.Assert(writer.GetEncodedLength() <= InitialCapacity); + return writer.Encode(); + } + + public override byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm) + { + ArgumentNullException.ThrowIfNull(data); + + // Ignore the hashAlgorithm parameter. + // This generator only supports SLH-DSA "Pure" signatures, but the overall design of + // CertificateRequest makes it easy for a hashAlgorithm value to get here. + + byte[] signature = new byte[_key.Algorithm.SignatureSizeInBytes]; + int written = _key.SignData(data, signature); + Debug.Assert(written == signature.Length); + return signature; + } + + protected override PublicKey BuildPublicKey() + { + Oid oid = new Oid(_key.Algorithm.Oid, null); + byte[] pkBytes = _key.ExportSlhDsaPublicKey(); + + return new PublicKey( + oid, + null, + new AsnEncodedData(oid, pkBytes, skipCopy: true)); + } + } +} diff --git a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509Certificate2.cs b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509Certificate2.cs index d6793583301..1062b5869f2 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509Certificate2.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509Certificate2.cs @@ -982,6 +982,98 @@ public X509Certificate2 CopyWithPrivateKey(MLDsa privateKey) return new X509Certificate2(pal); } + /// + /// Gets the public key from this certificate. + /// + /// + /// The public key, or if this certificate does not have an SLH-DSA public key. + /// + /// + /// The certificate has an SLH-DSA public key, but the platform does not support SLH-DSA. + /// + /// + /// The public key was invalid, or otherwise could not be imported. + /// + [Experimental(Experimentals.PostQuantumCryptographyDiagId)] + public SlhDsa? GetSlhDsaPublicKey() + { + if (!Helpers.IsSlhDsaOid(GetKeyAlgorithm())) + { + return null; + } + + Debug.Assert(!OperatingSystem.IsBrowser()); + return PublicKey.GetSlhDsaPublicKey(); + } + + /// + /// Gets the private key from this certificate. + /// + /// + /// The private key, or if this certificate does not have an SLH-DSA private key. + /// + /// + /// An error occurred accessing the private key. + /// + [Experimental(Experimentals.PostQuantumCryptographyDiagId)] + public SlhDsa? GetSlhDsaPrivateKey() => + Helpers.IsSlhDsaOid(GetKeyAlgorithm()) + ? Pal.GetSlhDsaPrivateKey() + : null; + + /// + /// Combines a private key with a certificate containing the associated public key into a + /// new instance that can access the private key. + /// + /// + /// The SLH-DSA private key that corresponds to the SLH-DSA public key in this certificate. + /// + /// + /// A new certificate with the property set to . + /// The current certificate isn't modified. + /// + /// + /// is . + /// + /// + /// The specified private key doesn't match the public key for this certificate. + /// + /// + /// The certificate already has an associated private key. + /// + [Experimental(Experimentals.PostQuantumCryptographyDiagId)] + public X509Certificate2 CopyWithPrivateKey(SlhDsa privateKey) + { + ArgumentNullException.ThrowIfNull(privateKey); + + if (HasPrivateKey) + throw new InvalidOperationException(SR.Cryptography_Cert_AlreadyHasPrivateKey); + + using (SlhDsa? publicKey = GetSlhDsaPublicKey()) + { + if (publicKey is null) + { + throw new ArgumentException(SR.Cryptography_PrivateKey_WrongAlgorithm); + } + + if (publicKey.Algorithm != privateKey.Algorithm) + { + throw new ArgumentException(SR.Cryptography_PrivateKey_DoesNotMatch, nameof(privateKey)); + } + + byte[] pk1 = publicKey.ExportSlhDsaPublicKey(); + byte[] pk2 = privateKey.ExportSlhDsaPublicKey(); + + if (!pk1.AsSpan().SequenceEqual(pk2)) + { + throw new ArgumentException(SR.Cryptography_PrivateKey_DoesNotMatch, nameof(privateKey)); + } + } + + ICertificatePal pal = Pal.CopyWithPrivateKey(privateKey); + return new X509Certificate2(pal); + } + /// /// Creates a new X509 certificate from the file contents of an RFC 7468 PEM-encoded /// certificate and private key. @@ -1172,24 +1264,30 @@ public static X509Certificate2 CreateFromPem(ReadOnlySpan certPem, ReadOnl s_DsaPublicKeyPrivateKeyLabels, static keyPem => CreateAndImport(keyPem, DSA.Create), certificate.CopyWithPrivateKey), - Oids.EcPublicKey when IsECDsa(certificate) => - ExtractKeyFromPem( - keyPem, - s_EcPublicKeyPrivateKeyLabels, - static keyPem => CreateAndImport(keyPem, ECDsa.Create), - certificate.CopyWithPrivateKey), Oids.EcPublicKey when IsECDiffieHellman(certificate) => ExtractKeyFromPem( keyPem, s_EcPublicKeyPrivateKeyLabels, static keyPem => CreateAndImport(keyPem, ECDiffieHellman.Create), certificate.CopyWithPrivateKey), + Oids.EcPublicKey when IsECDsa(certificate) => + ExtractKeyFromPem( + keyPem, + s_EcPublicKeyPrivateKeyLabels, + static keyPem => CreateAndImport(keyPem, ECDsa.Create), + certificate.CopyWithPrivateKey), Oids.MlKem512 or Oids.MlKem768 or Oids.MlKem1024 => ExtractKeyFromPem( keyPem, [PemLabels.Pkcs8PrivateKey], MLKem.ImportFromPem, certificate.CopyWithPrivateKey), + _ when Helpers.IsSlhDsaOid(keyAlgorithm) => + ExtractKeyFromPem( + keyPem, + [PemLabels.Pkcs8PrivateKey], + SlhDsa.ImportFromPem, + certificate.CopyWithPrivateKey), _ => throw new CryptographicException(SR.Format(SR.Cryptography_UnknownKeyAlgorithm, keyAlgorithm)), }; } @@ -1259,24 +1357,30 @@ public static X509Certificate2 CreateFromEncryptedPem(ReadOnlySpan certPem password, static (keyPem, password) => CreateAndImportEncrypted(keyPem, password, DSA.Create), certificate.CopyWithPrivateKey), - Oids.EcPublicKey when IsECDsa(certificate) => - ExtractKeyFromEncryptedPem( - keyPem, - password, - static (keyPem, password) => CreateAndImportEncrypted(keyPem, password, ECDsa.Create), - certificate.CopyWithPrivateKey), Oids.EcPublicKey when IsECDiffieHellman(certificate) => ExtractKeyFromEncryptedPem( keyPem, password, static (keyPem, password) => CreateAndImportEncrypted(keyPem, password, ECDiffieHellman.Create), certificate.CopyWithPrivateKey), + Oids.EcPublicKey when IsECDsa(certificate) => + ExtractKeyFromEncryptedPem( + keyPem, + password, + static (keyPem, password) => CreateAndImportEncrypted(keyPem, password, ECDsa.Create), + certificate.CopyWithPrivateKey), Oids.MlKem512 or Oids.MlKem768 or Oids.MlKem1024 => ExtractKeyFromEncryptedPem( keyPem, password, MLKem.ImportFromEncryptedPem, certificate.CopyWithPrivateKey), + _ when Helpers.IsSlhDsaOid(keyAlgorithm) => + ExtractKeyFromEncryptedPem( + keyPem, + password, + SlhDsa.ImportFromEncryptedPem, + certificate.CopyWithPrivateKey), _ => throw new CryptographicException(SR.Format(SR.Cryptography_UnknownKeyAlgorithm, keyAlgorithm)), }; } diff --git a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509CertificateLoader.OpenSsl.cs b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509CertificateLoader.OpenSsl.cs index de459c9854d..249f0fa6cdc 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509CertificateLoader.OpenSsl.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509CertificateLoader.OpenSsl.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using Internal.Cryptography; using Microsoft.Win32.SafeHandles; namespace System.Security.Cryptography.X509Certificates @@ -71,6 +72,8 @@ private static partial Pkcs12Return FromCertAndKey(CertAndKey certAndKey, Import return new AsymmetricAlgorithmPkcs12PrivateKey(pkcs8, static () => new DSAOpenSsl()); case Oids.MlKem512 or Oids.MlKem768 or Oids.MlKem1024: return new MLKemPkcs12PrivateKey(pkcs8); + case string when Helpers.IsSlhDsaOid(algorithm): + return new SlhDsaPkcs12PrivateKey(pkcs8); default: return null; } @@ -96,6 +99,13 @@ internal static SafeEvpPKeyHandle GetPrivateKey(Pkcs12Key key) return impl.DuplicateHandle(); } + if (key.Key is SlhDsa slhDsa) + { + SlhDsaImplementation? impl = slhDsa as SlhDsaImplementation; + Debug.Assert(impl is not null, "SlhDsa implementation is not handled for duplicating a handle."); + return impl.DuplicateHandle(); + } + return ((ECDiffieHellmanOpenSsl)key.Key).DuplicateKeyHandle(); } diff --git a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509CertificateLoader.Unix.cs b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509CertificateLoader.Unix.cs index 6becb4781a8..ab3fd947994 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509CertificateLoader.Unix.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509CertificateLoader.Unix.cs @@ -651,6 +651,29 @@ internal override bool TryExportSubjectPublicKeyInfo(Span destination, out internal override MLKem Key => _key; } + internal sealed class SlhDsaPkcs12PrivateKey : Pkcs12Key + { + private readonly SlhDsa _key; + + internal SlhDsaPkcs12PrivateKey(ReadOnlySpan pkcs8) + { + try + { + _key = SlhDsa.ImportPkcs8PrivateKey(pkcs8); + } + catch (PlatformNotSupportedException nse) + { + // PKCS12 loader turns PNSE in to a CryptographicException + throw new CryptographicException(SR.Cryptography_NotValidPrivateKey, nse); + } + } + + internal override bool TryExportSubjectPublicKeyInfo(Span destination, out int bytesWritten) => + _key.TryExportSubjectPublicKeyInfo(destination, out bytesWritten); + + internal override SlhDsa Key => _key; + } + internal sealed class AsymmetricAlgorithmPkcs12PrivateKey : Pkcs12Key { private readonly AsymmetricAlgorithm _key; diff --git a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509SignatureGenerator.cs b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509SignatureGenerator.cs index 8ebffa82e10..0de46ce56e1 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509SignatureGenerator.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509SignatureGenerator.cs @@ -54,5 +54,25 @@ public static X509SignatureGenerator CreateForMLDsa(MLDsa key) return new MLDsaX509SignatureGenerator(key); } + + /// + /// Creates a signature generator for SLH-DSA signatures using the specified key. + /// + /// + /// The private key. + /// + /// + /// An object for SLH-DSA signatures. + /// + /// + /// is . + /// + [Experimental(Experimentals.PostQuantumCryptographyDiagId)] + public static X509SignatureGenerator CreateForSlhDsa(SlhDsa key) + { + ArgumentNullException.ThrowIfNull(key); + + return new SlhDsaX509SignatureGenerator(key); + } } } diff --git a/src/runtime/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj b/src/runtime/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj index c06afade783..464cb696f6c 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj +++ b/src/runtime/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj @@ -358,6 +358,8 @@ Link="CommonTest\System\Security\Cryptography\AlgorithmImplementations\SlhDsa\SlhDsaPlatformTests.cs" /> + ( + "subjectName", + () => new CertificateRequest(subjectName, key)); + + subjectName = ""; + + AssertExtensions.Throws( + "key", + () => new CertificateRequest(subjectName, key)); + } + + [Fact] + public static void CtorValidation_SlhDsa_X500DN() + { + X500DistinguishedName subjectName = null; + SlhDsa key = null; + + AssertExtensions.Throws( + "subjectName", + () => new CertificateRequest(subjectName, key)); + + subjectName = new X500DistinguishedName(""); + + AssertExtensions.Throws( + "key", + () => new CertificateRequest(subjectName, key)); + } + + [Fact] + public static void SlhDsa_DoesNotSetHashAlgorithm() + { + using (SlhDsaMockImplementation key = SlhDsaMockImplementation.Create(SlhDsaAlgorithm.SlhDsaSha2_128f)) + { + key.ExportSlhDsaPublicKeyCoreHook = _ => { }; + CertificateRequest req = new CertificateRequest("CN=Test", key); + Assert.Null(req.HashAlgorithm.Name); + } + } + [Fact] public static void CtorValidation_PublicKey_X500DN() { diff --git a/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs b/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs index 7276ec4793c..a4c0af01495 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestChainTests.cs @@ -69,6 +69,27 @@ public static void CreateChain_RSA() } } + [ConditionalFact(typeof(SlhDsa), nameof(SlhDsa.IsSupported))] + public static void CreateChain_SlhDsa() + { + using (SlhDsa rootKey = SlhDsa.GenerateKey(SlhDsaAlgorithm.SlhDsaSha2_128f)) + using (SlhDsa intermed1Key = SlhDsa.GenerateKey(SlhDsaAlgorithm.SlhDsaSha2_128f)) + using (SlhDsa intermed2Key = SlhDsa.GenerateKey(SlhDsaAlgorithm.SlhDsaSha2_128f)) + using (SlhDsa leafKey = SlhDsa.GenerateKey(SlhDsaAlgorithm.SlhDsaSha2_128f)) + { + byte[] pubKey = leafKey.ExportSlhDsaPublicKey(); + + using (SlhDsa leafPubKey = SlhDsa.ImportSlhDsaPublicKey(leafKey.Algorithm, pubKey)) + { + CreateAndTestChain( + rootKey, + intermed1Key, + intermed2Key, + leafPubKey); + } + } + } + [Fact] public static void CreateChain_Hybrid() { @@ -233,6 +254,7 @@ private static CertificateRequest OpenCertRequest( ECDsa ecdsa => new CertificateRequest(x500dn, ecdsa, hashAlgorithm), ECDiffieHellman ecdh => new CertificateRequest(x500dn, new PublicKey(ecdh), hashAlgorithm), MLDsa mldsa => new CertificateRequest(x500dn, mldsa), + SlhDsa slhdsa => new CertificateRequest(x500dn, slhdsa), _ => throw new InvalidOperationException( $"Had no handler for key of type {key?.GetType().FullName ?? "null"}") }; @@ -245,6 +267,7 @@ private static X509SignatureGenerator OpenGenerator(object key) RSA rsa => X509SignatureGenerator.CreateForRSA(rsa, RSASignaturePadding.Pkcs1), ECDsa ecdsa => X509SignatureGenerator.CreateForECDsa(ecdsa), MLDsa mldsa => X509SignatureGenerator.CreateForMLDsa(mldsa), + SlhDsa slhdsa => X509SignatureGenerator.CreateForSlhDsa(slhdsa), _ => throw new InvalidOperationException( $"Had no handler for key of type {key?.GetType().FullName ?? "null"}") }; diff --git a/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs b/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs index f96046145e6..418552c4ea1 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CertificateRequestLoadTests.cs @@ -783,6 +783,32 @@ public static void Load_NoHashAlgorithm_OKForMLDsa() } } + [ConditionalFact(typeof(SlhDsa), nameof(SlhDsa.IsSupported))] + public static void Load_NoHashAlgorithm_OKForSlhDsa() + { + CertificateRequest req = CertificateRequest.LoadSigningRequestPem( + TestData.BigExponentPkcs10Pem, + default, + CertificateRequestLoadOptions.SkipSignatureValidation); + + DateTimeOffset now = DateTimeOffset.UtcNow; + DateTimeOffset notBefore = now.AddMonths(-1); + DateTimeOffset notAfter = now.AddMonths(1); + + using (SlhDsa key = SlhDsa.GenerateKey(SlhDsaAlgorithm.SlhDsaSha2_128f)) + { + // Assert.NoThrow + using X509Certificate2 cert = req.Create( + req.SubjectName, + X509SignatureGenerator.CreateForSlhDsa(key), + notBefore, + notAfter, + new byte[] { 3, 1, 0, 1, 3, 3, 3 }); + + Assert.Equal("2.16.840.1.101.3.4.3.21", cert.SignatureAlgorithm.Value); + } + } + [Fact] public static void LoadCreate_MatchesCreate_RSAPkcs1() { @@ -842,6 +868,18 @@ public static void LoadCreate_MatchesCreate_MLDsa() } } + [ConditionalFact(typeof(SlhDsa), nameof(SlhDsa.IsSupported))] + public static void LoadCreate_MatchesCreate_SlhDsa() + { + using (SlhDsa key = SlhDsa.GenerateKey(SlhDsaAlgorithm.SlhDsaSha2_128f)) + { + LoadCreate_MatchesCreate( + new CertificateRequest("CN=Roundtrip, O=SLH-DSA", key), + X509SignatureGenerator.CreateForSlhDsa(key), + deterministicSignature: false); + } + } + private static void LoadCreate_MatchesCreate( CertificateRequest request, X509SignatureGenerator generator, diff --git a/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs b/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs index b50299868a5..6723283a950 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/CrlBuilderTests.cs @@ -22,6 +22,7 @@ public enum CertKind MLDsa, RsaPkcs1, RsaPss, + SlhDsa, } public static IEnumerable SupportedCertKinds() @@ -35,6 +36,11 @@ public static IEnumerable SupportedCertKinds() yield return new object[] { CertKind.RsaPkcs1 }; yield return new object[] { CertKind.RsaPss }; + + if (SlhDsa.IsSupported) + { + yield return new object[] { CertKind.SlhDsa }; + } } public static IEnumerable NoHashAlgorithmCertKinds() @@ -43,6 +49,11 @@ public static IEnumerable NoHashAlgorithmCertKinds() { yield return new object[] { CertKind.MLDsa }; } + + if (SlhDsa.IsSupported) + { + yield return new object[] { CertKind.SlhDsa }; + } } [Fact] @@ -1533,6 +1544,12 @@ private static void BuildCertificateAndRun( key = mldsa; req = new CertificateRequest(subjectName, mldsa); } + else if (certKind == CertKind.SlhDsa) + { + SlhDsa slhDsa = SlhDsa.GenerateKey(SlhDsaAlgorithm.SlhDsaSha2_128f); + key = slhDsa; + req = new CertificateRequest(subjectName, slhDsa); + } else { throw new NotSupportedException($"Unsupported CertKind: {certKind}"); @@ -1697,6 +1714,12 @@ private static X509SignatureGenerator GetSignatureGenerator( key = mldsa; return X509SignatureGenerator.CreateForMLDsa(mldsa); } + else if (certKind == CertKind.SlhDsa) + { + SlhDsa slhDsa = cert.GetSlhDsaPrivateKey(); + key = slhDsa; + return X509SignatureGenerator.CreateForSlhDsa(slhDsa); + } else { throw new NotSupportedException($"Unsupported CertKind: {certKind}"); @@ -1727,6 +1750,11 @@ private static void VerifySignature( using MLDsa mldsa = cert.GetMLDsaPublicKey(); signatureValid = mldsa.VerifyData(data, signature); } + else if (certKind == CertKind.SlhDsa) + { + using SlhDsa slhDsa = cert.GetSlhDsaPublicKey(); + signatureValid = slhDsa.VerifyData(data, signature); + } else { throw new NotSupportedException($"Unsupported CertKind: {certKind}"); @@ -1743,7 +1771,7 @@ private static bool RequiresHashAlgorithm(CertKind certKind) return certKind switch { CertKind.ECDsa or CertKind.RsaPkcs1 or CertKind.RsaPss => true, - CertKind.MLDsa => false, + CertKind.MLDsa or CertKind.SlhDsa => false, _ => throw new NotSupportedException(certKind.ToString()) }; } diff --git a/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/PrivateKeyAssociationTests.cs b/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/PrivateKeyAssociationTests.cs index e736896cacd..a890299fbde 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/PrivateKeyAssociationTests.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/CertificateCreation/PrivateKeyAssociationTests.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography.SLHDsa.Tests; using System.Security.Cryptography.Tests; using Test.Cryptography; using Xunit; @@ -844,6 +846,86 @@ public static void CheckCopyWithPrivateKey_MLKem_OtherMLKem_DecapsulationKey() } } + [ConditionalFact(typeof(SlhDsa), nameof(SlhDsa.IsSupported))] + public static void CheckCopyWithPrivateKey_SlhDsa() + { + string certPem = PemEncoding.WriteString("CERTIFICATE", SlhDsaTestData.IetfSlhDsaSha2_128sCertificate); + + using (X509Certificate2 pubOnly = X509Certificate2.CreateFromPem(certPem)) + using (SlhDsa privKey = SlhDsa.ImportPkcs8PrivateKey(SlhDsaTestData.IetfSlhDsaSha2_128sPrivateKeyPkcs8)) + using (X509Certificate2 wrongAlg = X509CertificateLoader.LoadCertificate(TestData.CertWithEnhancedKeyUsage)) + { + CheckCopyWithPrivateKey( + pubOnly, + wrongAlg, + privKey, + [ + () => SlhDsa.GenerateKey(SlhDsaAlgorithm.SlhDsaSha2_128s), + () => SlhDsa.GenerateKey(SlhDsaAlgorithm.SlhDsaSha2_192f), + () => SlhDsa.GenerateKey(SlhDsaAlgorithm.SlhDsaShake256f), + ], + (cert, key) => cert.CopyWithPrivateKey(key), + cert => cert.GetSlhDsaPublicKey(), + cert => cert.GetSlhDsaPrivateKey(), + (priv, pub) => + { + byte[] data = new byte[RandomNumberGenerator.GetInt32(97)]; + RandomNumberGenerator.Fill(data); + + byte[] signature = new byte[pub.Algorithm.SignatureSizeInBytes]; + int written = priv.SignData(data, signature); + Assert.Equal(signature.Length, written); + Assert.True(pub.VerifyData(data, signature)); + }); + } + } + + [ConditionalFact(typeof(SlhDsa), nameof(SlhDsa.IsSupported))] + public static void CheckCopyWithPrivateKey_SlhDsa_OtherSlhDsa() + { + string certPem = PemEncoding.WriteString("CERTIFICATE", SlhDsaTestData.IetfSlhDsaSha2_128sCertificate); + + using (X509Certificate2 pubOnly = X509Certificate2.CreateFromPem(certPem)) + { + using (SlhDsaMockImplementation publicSlhDsa = SlhDsaMockImplementation.Create(SlhDsaAlgorithm.SlhDsaSha2_128s)) + { + Exception e = new Exception("no secret key"); + publicSlhDsa.ExportSlhDsaSecretKeyCoreHook = _ => throw e; + publicSlhDsa.ExportSlhDsaPublicKeyCoreHook = (Span destination) => + SlhDsaTestData.IetfSlhDsaSha2_128sPublicKeyValue.CopyTo(destination); + + Assert.Same(e, AssertExtensions.Throws(() => pubOnly.CopyWithPrivateKey(publicSlhDsa))); + } + + SlhDsaMockImplementation privateSlhDsa = SlhDsaMockImplementation.Create(SlhDsaAlgorithm.SlhDsaSha2_128s); + privateSlhDsa.ExportSlhDsaPublicKeyCoreHook = (Span destination) => + SlhDsaTestData.IetfSlhDsaSha2_128sPublicKeyValue.CopyTo(destination); + privateSlhDsa.ExportSlhDsaSecretKeyCoreHook = (Span destination) => + SlhDsaTestData.IetfSlhDsaSha2_128sPrivateKeyValue.CopyTo(destination); + + using (X509Certificate2 privCert = pubOnly.CopyWithPrivateKey(privateSlhDsa)) + { + AssertExtensions.TrueExpression(privCert.HasPrivateKey); + + using (SlhDsa certPrivateSlhDsa = privCert.GetSlhDsaPrivateKey()) + { + AssertExtensions.SequenceEqual( + SlhDsaTestData.IetfSlhDsaSha2_128sPrivateKeyValue, + certPrivateSlhDsa.ExportSlhDsaSecretKey()); + + privateSlhDsa.Dispose(); + privateSlhDsa.ExportSlhDsaPublicKeyCoreHook = _ => Assert.Fail(); + privateSlhDsa.ExportSlhDsaSecretKeyCoreHook = _ => Assert.Fail(); + + // Ensure the key is actual a clone + AssertExtensions.SequenceEqual( + SlhDsaTestData.IetfSlhDsaSha2_128sPrivateKeyValue, + certPrivateSlhDsa.ExportSlhDsaSecretKey()); + } + } + } + } + private static void CheckCopyWithPrivateKey( X509Certificate2 cert, X509Certificate2 wrongAlgorithmCert, diff --git a/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/ExportTests.cs b/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/ExportTests.cs index 206d818bf88..a7a54c81d3f 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/ExportTests.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/ExportTests.cs @@ -7,6 +7,7 @@ using System.Security.Cryptography.Tests; using System.Security.Cryptography.Dsa.Tests; using System.Security.Cryptography.EcDsa.Tests; +using System.Security.Cryptography.SLHDsa.Tests; using System.Security.Cryptography.Asn1; using System.Security.Cryptography.Asn1.Pkcs7; using System.Security.Cryptography.Asn1.Pkcs12; @@ -390,6 +391,66 @@ public static void ExportPkcs12_MLKem_Roundtrip(MLKemAlgorithm algorithm) } } + [ConditionalFact(typeof(SlhDsa), nameof(SlhDsa.IsSupported))] + public static void ExportPkcs12_SlhDsa_Ietf_Roundtrip() + { + const string password = "PLACEHOLDER"; + byte[] pfxBytes = SlhDsaTestData.IetfSlhDsaSha2_128sCertificatePfx; + + PbeParameters pbeParameters = new(PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, 32); + + using (X509Certificate2 cert = X509CertificateLoader.LoadPkcs12(pfxBytes, password)) + { + byte[] pkcs12 = cert.ExportPkcs12(pbeParameters, password); + (int certs, int keys) = VerifyPkcs12( + pkcs12, + password, + pbeParameters.IterationCount, + pbeParameters.HashAlgorithm, + pbeParameters.EncryptionAlgorithm); + Assert.Equal(1, certs); + Assert.Equal(1, keys); + + using (X509Certificate2 reLoaded = X509CertificateLoader.LoadPkcs12(pkcs12, password)) + using (SlhDsa slhDsa = reLoaded.GetSlhDsaPrivateKey()) + { + Assert.NotNull(slhDsa); + Assert.Equal(SlhDsaAlgorithm.SlhDsaSha2_128s, slhDsa.Algorithm); + AssertExtensions.SequenceEqual(SlhDsaTestData.IetfSlhDsaSha2_128sPrivateKeyValue, slhDsa.ExportSlhDsaSecretKey()); + } + } + } + + [ConditionalTheory(typeof(SlhDsa), nameof(SlhDsa.IsSupported))] + [MemberData(nameof(SlhDsaTestData.GeneratedKeyInfosData), MemberType = typeof(SlhDsaTestData))] + public static void ExportPkcs12_SlhDsa_Generated_Roundtrip(SlhDsaTestData.SlhDsaGeneratedKeyInfo info) + { + string password = info.EncryptionPassword; + PbeParameters pbeParameters = new(PbeEncryptionAlgorithm.Aes256Cbc, HashAlgorithmName.SHA256, 32); + + using (X509Certificate2 cert = X509CertificateLoader.LoadPkcs12(info.SelfSignedCertificatePfx, password)) + { + byte[] pkcs12 = cert.ExportPkcs12(pbeParameters, password); + (int certs, int keys) = VerifyPkcs12( + pkcs12, + password, + pbeParameters.IterationCount, + pbeParameters.HashAlgorithm, + pbeParameters.EncryptionAlgorithm); + Assert.Equal(1, certs); + Assert.Equal(1, keys); + + using (X509Certificate2 reLoaded = X509CertificateLoader.LoadPkcs12(pkcs12, password)) + using (SlhDsa slhDsa = reLoaded.GetSlhDsaPrivateKey()) + { + Assert.NotNull(slhDsa); + Assert.Equal(info.Algorithm, slhDsa.Algorithm); + AssertExtensions.SequenceEqual(info.SecretKey, slhDsa.ExportSlhDsaSecretKey()); + AssertExtensions.SequenceEqual(info.Certificate, reLoaded.RawData); + } + } + } + [Fact] [PlatformSpecific(TestPlatforms.Windows)] [OuterLoop("Modifies user-persisted state", ~TestPlatforms.Browser)] diff --git a/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/PfxTests.cs b/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/PfxTests.cs index 43e2aa06118..ef10e1798e6 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/PfxTests.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/PfxTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Security.Cryptography.SLHDsa.Tests; using System.Security.Cryptography.Tests; using System.Text; using Microsoft.DotNet.RemoteExecutor; @@ -662,6 +663,58 @@ public static void ReadMLKem512PrivateKey_NotSupported(X509KeyStorageFlags keySt } } + [ConditionalTheory(typeof(SlhDsa), nameof(SlhDsa.IsSupported))] + [MemberData(nameof(StorageFlags))] + public static void ReadSlhDsa_Pfx_Ietf(X509KeyStorageFlags keyStorageFlags) + { + byte[] pfxBytes = SlhDsaTestData.IetfSlhDsaSha2_128sCertificatePfx; + string pfxPassword = "PLACEHOLDER"; + + using (X509Certificate2 cert = X509CertificateLoader.LoadPkcs12(pfxBytes, pfxPassword, keyStorageFlags)) + using (SlhDsa slhDsa = cert.GetSlhDsaPrivateKey()) + { + Assert.NotNull(slhDsa); + Assert.Equal(SlhDsaAlgorithm.SlhDsaSha2_128s, slhDsa.Algorithm); + // Note this display string is reversed from the one in the IETF example but equivalent. + Assert.Equal("O=Bogus SLH-DSA-SHA2-128s CA, L=Paris, C=FR", cert.Subject); + AssertExtensions.SequenceEqual(SlhDsaTestData.IetfSlhDsaSha2_128sPrivateKeyValue, slhDsa.ExportSlhDsaSecretKey()); + } + } + + [ConditionalTheory(typeof(SlhDsaTestHelpers), nameof(SlhDsaTestHelpers.SlhDsaIsNotSupported))] + [MemberData(nameof(StorageFlags))] + public static void ReadSlhDsa_Pfx_Ietf_NotSupported(X509KeyStorageFlags keyStorageFlags) + { + byte[] pfxBytes = SlhDsaTestData.IetfSlhDsaSha2_128sCertificatePfx_Pbes1; + string pfxPassword = "PLACEHOLDER"; + + // Windows when using non-ephemeral delays throwing no private key and instead acts as it the + // keyset does not exist. Exporting it again to PFX forces Windows to reconcile the fact the key + // didn't actually load. + if (PlatformDetection.IsWindows && keyStorageFlags != X509KeyStorageFlags.EphemeralKeySet) + { + using (X509Certificate2 cert = X509CertificateLoader.LoadPkcs12(pfxBytes, pfxPassword, keyStorageFlags)) + { + Assert.Throws( + () => cert.ExportPkcs12(Pkcs12ExportPbeParameters.Pbes2Aes256Sha256, pfxPassword)); + } + + using (X509Certificate2 cert = new(pfxBytes, pfxPassword, keyStorageFlags)) + { + Assert.Throws( + () => cert.ExportPkcs12(Pkcs12ExportPbeParameters.Pbes2Aes256Sha256, pfxPassword)); + } + } + else + { + Assert.Throws( + () => X509CertificateLoader.LoadPkcs12(pfxBytes, pfxPassword, keyStorageFlags)); + + Assert.Throws( + () => new X509Certificate2(pfxBytes, pfxPassword, keyStorageFlags)); + } + } + #if !NO_EPHEMERALKEYSET_AVAILABLE [Fact] [PlatformSpecific(TestPlatforms.Windows)] // Uses P/Invokes diff --git a/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/PublicKeyTests.cs b/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/PublicKeyTests.cs index eaf3298a61a..7add39b7602 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/PublicKeyTests.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/PublicKeyTests.cs @@ -3,9 +3,9 @@ using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; +using System.Security.Cryptography.SLHDsa.Tests; using System.Security.Cryptography.Tests; +using Microsoft.Diagnostics.Runtime.Interop; using Test.Cryptography; using Xunit; @@ -677,16 +677,7 @@ public static void ExportSubjectPublicKeyInfo_RSA() rsa.ImportFromPem(TestData.RsaPkcs8PublicKey); PublicKey key = new PublicKey(rsa); - Span algSpki = rsa.ExportSubjectPublicKeyInfo(); - Assert.True(algSpki.SequenceEqual(key.ExportSubjectPublicKeyInfo()), "SequenceEquals(ExportSubjectPublicKeyInfo)"); - - // Just right - Assert.True(key.TryExportSubjectPublicKeyInfo(algSpki, out int written), nameof(key.TryExportSubjectPublicKeyInfo)); - Assert.Equal(algSpki.Length, written); - - // Too small - Assert.False(key.TryExportSubjectPublicKeyInfo(algSpki.Slice(1), out written), nameof(key.TryExportSubjectPublicKeyInfo)); - Assert.Equal(0, written); + AssertExportSubjectPublicKeyInfo(key, rsa.ExportSubjectPublicKeyInfo()); } [Fact] @@ -697,16 +688,7 @@ public static void ExportSubjectPublicKeyInfo_DSA() dsa.ImportFromPem(TestData.DsaPkcs8PublicKey); PublicKey key = new PublicKey(dsa); - Span algSpki = dsa.ExportSubjectPublicKeyInfo(); - Assert.True(algSpki.SequenceEqual(key.ExportSubjectPublicKeyInfo()), "SequenceEquals(ExportSubjectPublicKeyInfo)"); - - // Just right - Assert.True(key.TryExportSubjectPublicKeyInfo(algSpki, out int written), nameof(key.TryExportSubjectPublicKeyInfo)); - Assert.Equal(algSpki.Length, written); - - // Too small - Assert.False(key.TryExportSubjectPublicKeyInfo(algSpki.Slice(1), out written), nameof(key.TryExportSubjectPublicKeyInfo)); - Assert.Equal(0, written); + AssertExportSubjectPublicKeyInfo(key, dsa.ExportSubjectPublicKeyInfo()); } [Fact] @@ -716,16 +698,7 @@ public static void ExportSubjectPublicKeyInfo_ECDSA() ecdsa.ImportFromPem(TestData.ECDsaPkcs8PublicKey); PublicKey key = new PublicKey(ecdsa); - Span algSpki = ecdsa.ExportSubjectPublicKeyInfo(); - Assert.True(algSpki.SequenceEqual(key.ExportSubjectPublicKeyInfo()), "SequenceEquals(ExportSubjectPublicKeyInfo)"); - - // Just right - Assert.True(key.TryExportSubjectPublicKeyInfo(algSpki, out int written), nameof(key.TryExportSubjectPublicKeyInfo)); - Assert.Equal(algSpki.Length, written); - - // Too small - Assert.False(key.TryExportSubjectPublicKeyInfo(algSpki.Slice(1), out written), nameof(key.TryExportSubjectPublicKeyInfo)); - Assert.Equal(0, written); + AssertExportSubjectPublicKeyInfo(key, ecdsa.ExportSubjectPublicKeyInfo()); } [Fact] @@ -735,16 +708,7 @@ public static void ExportSubjectPublicKeyInfo_ECDH() ecdh.ImportFromPem(TestData.EcDhPkcs8Key); PublicKey key = new PublicKey(ecdh); - Span algSpki = ecdh.ExportSubjectPublicKeyInfo(); - Assert.True(algSpki.SequenceEqual(key.ExportSubjectPublicKeyInfo()), "SequenceEquals(ExportSubjectPublicKeyInfo)"); - - // Just right - Assert.True(key.TryExportSubjectPublicKeyInfo(algSpki, out int written), nameof(key.TryExportSubjectPublicKeyInfo)); - Assert.Equal(algSpki.Length, written); - - // Too small - Assert.False(key.TryExportSubjectPublicKeyInfo(algSpki.Slice(1), out written), nameof(key.TryExportSubjectPublicKeyInfo)); - Assert.Equal(0, written); + AssertExportSubjectPublicKeyInfo(key, ecdh.ExportSubjectPublicKeyInfo()); } [ConditionalTheory(typeof(MLKem), nameof(MLKem.IsSupported))] @@ -754,25 +718,7 @@ public static void ExportSubjectPublicKeyInfo_MLKem(MLKemAlgorithm algorithm) using MLKem kem = MLKem.GenerateKey(algorithm); PublicKey key = new(kem); - Span algSpki = kem.ExportSubjectPublicKeyInfo(); - AssertExtensions.SequenceEqual(algSpki, key.ExportSubjectPublicKeyInfo().AsSpan()); - int expectedSize = algSpki.Length; - - // Just right - algSpki.Clear(); - Assert.True(key.TryExportSubjectPublicKeyInfo(algSpki, out int written), nameof(key.TryExportSubjectPublicKeyInfo)); - Assert.Equal(expectedSize, written); - AssertExtensions.SequenceEqual(algSpki, key.ExportSubjectPublicKeyInfo().AsSpan()); - - // Bigger than needed - algSpki = new byte[expectedSize + 42]; - Assert.True(key.TryExportSubjectPublicKeyInfo(algSpki, out written), nameof(key.TryExportSubjectPublicKeyInfo)); - Assert.Equal(expectedSize, written); - AssertExtensions.SequenceEqual(algSpki.Slice(0, written), key.ExportSubjectPublicKeyInfo().AsSpan()); - - // Too small - Assert.False(key.TryExportSubjectPublicKeyInfo(algSpki.Slice(0, 1), out written), nameof(key.TryExportSubjectPublicKeyInfo)); - Assert.Equal(0, written); + AssertExportSubjectPublicKeyInfo(key, kem.ExportSubjectPublicKeyInfo()); } [ConditionalTheory(typeof(MLKem), nameof(MLKem.IsSupported))] @@ -787,6 +733,28 @@ public static void ExportSubjectPublicKeyInfo_MLKem_Independent(MLKemAlgorithm a Assert.NotSame(spki1, spki2); } + [ConditionalTheory(typeof(SlhDsa), nameof(SlhDsa.IsSupported))] + [MemberData(nameof(SlhDsaTestData.AlgorithmsData), MemberType = typeof(SlhDsaTestData))] + public static void ExportSubjectPublicKeyInfo_SlhDsa(SlhDsaAlgorithm algorithm) + { + using SlhDsa slhDsa = SlhDsa.GenerateKey(algorithm); + PublicKey key = new(slhDsa); + + AssertExportSubjectPublicKeyInfo(key, slhDsa.ExportSubjectPublicKeyInfo()); + } + + [ConditionalTheory(typeof(SlhDsa), nameof(SlhDsa.IsSupported))] + [MemberData(nameof(SlhDsaTestData.AlgorithmsData), MemberType = typeof(SlhDsaTestData))] + public static void ExportSubjectPublicKeyInfo_SlhDsa_Independent(SlhDsaAlgorithm algorithm) + { + using SlhDsa slhDsa = SlhDsa.GenerateKey(algorithm); + PublicKey key = new(slhDsa); + + byte[] spki1 = slhDsa.ExportSubjectPublicKeyInfo(); + byte[] spki2 = slhDsa.ExportSubjectPublicKeyInfo(); + Assert.NotSame(spki1, spki2); + } + [Fact] public static void CreateFromSubjectPublicKeyInfo_Roundtrip_RSA() { @@ -1116,5 +1084,27 @@ private static void TestKey_ECDsaCng(byte[] certBytes, TestData.ECDsaCngKeyValue } } } + + private static void AssertExportSubjectPublicKeyInfo(PublicKey key, Span algSpki) + { + AssertExtensions.SequenceEqual(algSpki, key.ExportSubjectPublicKeyInfo().AsSpan()); + int expectedSize = algSpki.Length; + + // Just right + algSpki.Clear(); + Assert.True(key.TryExportSubjectPublicKeyInfo(algSpki, out int written), nameof(key.TryExportSubjectPublicKeyInfo)); + Assert.Equal(expectedSize, written); + AssertExtensions.SequenceEqual(algSpki, key.ExportSubjectPublicKeyInfo().AsSpan()); + + // Bigger than needed + algSpki = new byte[expectedSize + 42]; + Assert.True(key.TryExportSubjectPublicKeyInfo(algSpki, out written), nameof(key.TryExportSubjectPublicKeyInfo)); + Assert.Equal(expectedSize, written); + AssertExtensions.SequenceEqual(algSpki.Slice(0, written), key.ExportSubjectPublicKeyInfo().AsSpan()); + + // Too small + Assert.False(key.TryExportSubjectPublicKeyInfo(algSpki.Slice(0, 1), out written), nameof(key.TryExportSubjectPublicKeyInfo)); + Assert.Equal(0, written); + } } } diff --git a/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/X509Certificate2PemTests.cs b/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/X509Certificate2PemTests.cs index bf786fc7dc2..b05939f916d 100644 --- a/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/X509Certificate2PemTests.cs +++ b/src/runtime/src/libraries/System.Security.Cryptography/tests/X509Certificates/X509Certificate2PemTests.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; +using System.Security.Cryptography.SLHDsa.Tests; using System.Security.Cryptography.Tests; using Test.Cryptography; using Xunit; @@ -268,6 +269,54 @@ public static void CreateFromPem_ECDH_Pkcs8_Success() } } + [Fact] + public static void CreateFromPem_EC_Pkcs8_Success() + { + // ecPublicKey certificates that have no key usage restrictions should be allowed to be used as both + // an ECDsa key and an ECDiffieHellman key. + + // For purposes of creating the certificate, it doesn't matter if we use an ECDSA or ECDH key, but starting + // with ECDSA means we can make a self-signed cert. + using ECDsa key = ECDsa.Create(); + key.ImportFromPem(TestData.EcDhPkcs8Key); + CertificateRequest req = new("CN=radish", key, HashAlgorithmName.SHA256); + using X509Certificate2 cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(1)); + string pemAggregate = $"{cert.ExportCertificatePem()}\n{TestData.EcDhPkcs8Key}"; + using X509Certificate2 reLoaded = X509Certificate2.CreateFromPem(pemAggregate, pemAggregate); + + AssertKeysMatch(TestData.EcDhPkcs8Key, reLoaded.GetECDiffieHellmanPrivateKey); + AssertKeysMatch(TestData.EcDhPkcs8Key, reLoaded.GetECDsaPrivateKey); + AssertExtensions.SequenceEqual(cert.SerialNumberBytes.Span, reLoaded.SerialNumberBytes.Span); + } + + [Fact] + public static void CreateFromEncryptedPem_EC_Pkcs8_Success() + { + // ecPublicKey certificates that have no key usage restrictions should be allowed to be used as both + // an ECDsa key and an ECDiffieHellman key. + + // For purposes of creating the certificate, it doesn't matter if we use an ECDSA or ECDH key, but starting + // with ECDSA means we can make a self-signed cert. + using ECDsa key = ECDsa.Create(); + key.ImportFromPem(TestData.EcDhPkcs8Key); + CertificateRequest req = new("CN=radish", key, HashAlgorithmName.SHA256); + using X509Certificate2 cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(1)); + + PbeParameters pbe = new(PbeEncryptionAlgorithm.Aes128Cbc, HashAlgorithmName.SHA1, 32); + const string Password = "PLACEHOLDER"; + + string encryptedPrivateKey = PemEncoding.WriteString( + "ENCRYPTED PRIVATE KEY", + key.ExportEncryptedPkcs8PrivateKey(Password, pbe)); + + string pemAggregate = $"{cert.ExportCertificatePem()}\n{encryptedPrivateKey}"; + using X509Certificate2 reLoaded = X509Certificate2.CreateFromEncryptedPem(pemAggregate, pemAggregate, Password); + + AssertKeysMatch(encryptedPrivateKey, reLoaded.GetECDiffieHellmanPrivateKey, Password); + AssertKeysMatch(encryptedPrivateKey, reLoaded.GetECDsaPrivateKey, Password); + AssertExtensions.SequenceEqual(cert.SerialNumberBytes.Span, reLoaded.SerialNumberBytes.Span); + } + [ConditionalFact(typeof(MLKem), nameof(MLKem.IsSupported))] public static void CreateFromPem_MLKem_Pkcs8_Success() { @@ -395,6 +444,79 @@ public static void CreateFromEncryptedPem_MLKem_Pkcs8_Success() } } + [ConditionalFact(typeof(SlhDsa), nameof(SlhDsa.IsSupported))] + public static void CreateFromPem_SlhDsa_Pkcs8_Ietf_Success() + { + string certPem = PemEncoding.WriteString("CERTIFICATE", SlhDsaTestData.IetfSlhDsaSha2_128sCertificate); + string privateKeyPem = PemEncoding.WriteString("PRIVATE KEY", SlhDsaTestData.IetfSlhDsaSha2_128sPrivateKeyPkcs8); + + using (X509Certificate2 cert = X509Certificate2.CreateFromPem( + certPem, + privateKeyPem)) + { + Assert.Equal( + SlhDsaTestData.IetfSlhDsaSha2_128sCertificateThumbprint, + cert.GetCertHash(HashAlgorithmName.SHA1)); + AssertKeysMatch(privateKeyPem, cert.GetSlhDsaPrivateKey); + } + + using (SlhDsa slhDsa = SlhDsa.ImportPkcs8PrivateKey(SlhDsaTestData.IetfSlhDsaSha2_128sPrivateKeyPkcs8)) + { + const string password = "PLACEHOLDER"; + string encryptedPrivateKeyPem = slhDsa.ExportEncryptedPkcs8PrivateKeyPem( + password, + new PbeParameters(PbeEncryptionAlgorithm.Aes128Cbc, HashAlgorithmName.SHA384, 1)); + + using (X509Certificate2 cert = X509Certificate2.CreateFromEncryptedPem( + certPem, + encryptedPrivateKeyPem, + password)) + { + Assert.Equal( + SlhDsaTestData.IetfSlhDsaSha2_128sCertificateThumbprint, + cert.GetCertHash(HashAlgorithmName.SHA1)); + AssertKeysMatch(encryptedPrivateKeyPem, cert.GetSlhDsaPrivateKey, password); + } + } + } + + [ConditionalTheory(typeof(SlhDsa), nameof(SlhDsa.IsSupported))] + [MemberData(nameof(SlhDsaTestData.GeneratedKeyInfosData), MemberType = typeof(SlhDsaTestData))] + public static void CreateFromPem_SlhDsa_Pkcs8_Success(SlhDsaTestData.SlhDsaGeneratedKeyInfo info) + { + string certPem = PemEncoding.WriteString("CERTIFICATE", info.Certificate); + string privateKeyPem = PemEncoding.WriteString("PRIVATE KEY", info.Pkcs8PrivateKey); + + using (X509Certificate2 cert = X509Certificate2.CreateFromPem( + certPem, + privateKeyPem)) + { + Assert.Equal( + info.Thumbprint, + cert.GetCertHash(HashAlgorithmName.SHA1)); + AssertKeysMatch(privateKeyPem, cert.GetSlhDsaPrivateKey); + } + + using (SlhDsa slhDsa = SlhDsa.ImportPkcs8PrivateKey(info.Pkcs8PrivateKey)) + { + const string password = "PLACEHOLDER"; + string encryptedPrivateKeyPem = slhDsa.ExportEncryptedPkcs8PrivateKeyPem( + password, + new PbeParameters(PbeEncryptionAlgorithm.Aes128Cbc, HashAlgorithmName.SHA384, 1)); + + using (X509Certificate2 cert = X509Certificate2.CreateFromEncryptedPem( + certPem, + encryptedPrivateKeyPem, + password)) + { + Assert.Equal( + info.Thumbprint, + cert.GetCertHash(HashAlgorithmName.SHA1)); + AssertKeysMatch(encryptedPrivateKeyPem, cert.GetSlhDsaPrivateKey, password); + } + } + } + [Fact] [SkipOnPlatform(PlatformSupport.MobileAppleCrypto, "DSA is not available")] public static void CreateFromPem_Dsa_Pkcs8_Success() @@ -610,6 +732,10 @@ private static void AssertKeysMatch(string keyPem, Func keyLoader, string { alg = password is null ? MLKem.ImportFromPem(keyPem) : MLKem.ImportFromEncryptedPem(keyPem, password); } + else if (key is SlhDsa) + { + alg = password is null ? SlhDsa.ImportFromPem(keyPem) : SlhDsa.ImportFromEncryptedPem(keyPem, password); + } else { Assert.Fail($"Unhandled key type {key.GetType()}."); @@ -659,6 +785,12 @@ private static void AssertKeysMatch(string keyPem, Func keyLoader, string sharedSecret2 = kem.Decapsulate(ciphertext); AssertExtensions.SequenceEqual(sharedSecret1, sharedSecret2); break; + case (SlhDsa slhDsa, SlhDsa slhDsaPem): + + byte[] slhDsaSignature = new byte[slhDsa.Algorithm.SignatureSizeInBytes]; + Assert.Equal(slhDsaSignature.Length, slhDsa.SignData(data, slhDsaSignature)); + Assert.True(slhDsaPem.VerifyData(data, slhDsaSignature)); + break; default: throw new CryptographicException("Unknown key algorithm"); } diff --git a/src/runtime/src/mono/mono/mini/simd-intrinsics.c b/src/runtime/src/mono/mono/mini/simd-intrinsics.c index f9d8d4b59ef..069333c0a61 100644 --- a/src/runtime/src/mono/mono/mini/simd-intrinsics.c +++ b/src/runtime/src/mono/mono/mini/simd-intrinsics.c @@ -468,9 +468,11 @@ emit_simd_ins_for_unary_op (MonoCompile *cfg, MonoClass *klass, MonoMethodSignat switch (id) { case SN_Negate: + case SN_op_UnaryNegation: op = OP_NEGATION; break; case SN_OnesComplement: + case SN_op_OnesComplement: op = OP_WASM_ONESCOMPLEMENT; break; default: @@ -2182,7 +2184,7 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi case SN_Floor: { if (!type_enum_is_float (arg0_type)) return NULL; -#ifdef TARGET_ARM64 +#if defined(TARGET_ARM64) || defined(TARGET_WASM) int ceil_or_floor = id == SN_Ceiling ? INTRINS_SIMD_CEIL : INTRINS_SIMD_FLOOR; return emit_simd_ins_for_sig (cfg, klass, OP_XOP_OVR_X_X, ceil_or_floor, arg0_type, fsig, args); #elif defined(TARGET_AMD64) diff --git a/src/runtime/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.c b/src/runtime/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.c index 4f76a702c40..52900ee3aa3 100644 --- a/src/runtime/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.c +++ b/src/runtime/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.c @@ -3,6 +3,7 @@ #include #include "pal_evp_pkey.h" +#include "pal_evp_pkey_slh_dsa.h" #include "pal_utilities.h" #ifdef NEED_OPENSSL_3_0 @@ -137,6 +138,11 @@ int32_t CryptoNative_EvpPKeyFamily(const EVP_PKEY* key) } #endif + if (IsSlhDsaFamily(key)) + { + return PalPKeyFamilyId_SlhDsa; + } + return PalPKeyFamilyId_Unknown; } diff --git a/src/runtime/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.h b/src/runtime/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.h index b8ecc3654ad..4fe539211ed 100644 --- a/src/runtime/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.h +++ b/src/runtime/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey.h @@ -20,6 +20,7 @@ typedef enum PalPKeyFamilyId_DSA = 2, PalPKeyFamilyId_ECC = 3, PalPKeyFamilyId_MLKem = 4, + PalPKeyFamilyId_SlhDsa = 5, } PalPKeyFamilyId; typedef struct EvpPKeyExtraHandle_st EvpPKeyExtraHandle; diff --git a/src/runtime/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_slh_dsa.c b/src/runtime/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_slh_dsa.c index b8bc62c219a..a7f7302c155 100644 --- a/src/runtime/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_slh_dsa.c +++ b/src/runtime/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_slh_dsa.c @@ -278,3 +278,10 @@ int32_t CryptoNative_SlhDsaGetPalId(const EVP_PKEY* pKey, int32_t* slhDsaTypeId) *slhDsaTypeId = PalSlhDsaId_Unknown; return 0; } + +int32_t IsSlhDsaFamily(const EVP_PKEY* pKey) +{ + int slhDsaId = 0; + return CryptoNative_SlhDsaGetPalId(pKey, &slhDsaId) && + slhDsaId != PalSlhDsaId_Unknown; +} diff --git a/src/runtime/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_slh_dsa.h b/src/runtime/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_slh_dsa.h index 072514d4400..a5170d52ef4 100644 --- a/src/runtime/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_slh_dsa.h +++ b/src/runtime/src/native/libs/System.Security.Cryptography.Native/pal_evp_pkey_slh_dsa.h @@ -64,3 +64,8 @@ PALEXPORT int32_t CryptoNative_SlhDsaExportPublicKey(const EVP_PKEY* pKey, uint8 Get the SLH-DSA type ID for the given SLH-DSA key. */ PALEXPORT int32_t CryptoNative_SlhDsaGetPalId(const EVP_PKEY* pKey, int32_t* slhDsaTypeId); + +/* +Determine whether the given key is an SLH-DSA key. +*/ +int32_t IsSlhDsaFamily(const EVP_PKEY* pKey); diff --git a/src/runtime/src/native/managed/cdacreader/Directory.Build.targets b/src/runtime/src/native/managed/cdacreader/Directory.Build.targets new file mode 100644 index 00000000000..03af733f333 --- /dev/null +++ b/src/runtime/src/native/managed/cdacreader/Directory.Build.targets @@ -0,0 +1,4 @@ + + + + diff --git a/src/runtime/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_X86.cs b/src/runtime/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_X86.cs index 257209027df..5a71f3ccd3d 100644 --- a/src/runtime/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_X86.cs +++ b/src/runtime/src/tests/Common/GenerateHWIntrinsicTests/GenerateHWIntrinsicTests_X86.cs @@ -1817,6 +1817,10 @@ ("ImmBinOpTest.template", new Dictionary { ["Isa"] = "Avx10v2", ["LoadIsa"] = "Avx10v1", ["Method"] = "MinMaxScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["Imm"] = "2", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "result[0] != ((Math.Abs(left[0]) < Math.Abs(right[0])) ? left[0] : right[0])", ["ValidateRemainingResults"] = "result[i] != left[i]"}), ("ImmBinOpTest.template", new Dictionary { ["Isa"] = "Avx10v2", ["LoadIsa"] = "Avx10v1", ["Method"] = "MinMaxScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["Imm"] = "3", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "result[0] != ((Math.Abs(left[0]) > Math.Abs(right[0])) ? left[0] : right[0])", ["ValidateRemainingResults"] = "result[i] != left[i]"}), ("ImmBinOpTest.template", new Dictionary { ["Isa"] = "Avx10v2", ["LoadIsa"] = "Avx10v1", ["Method"] = "MinMaxScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["Imm"] = "3", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "result[0] != ((Math.Abs(left[0]) > Math.Abs(right[0])) ? left[0] : right[0])", ["ValidateRemainingResults"] = "result[i] != left[i]"}), + ("SimpleUnOpTest.template", new Dictionary { ["Isa"] = "Avx10v2", ["LoadIsa"] = "Avx10v1", ["Method"] = "MoveScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateFirstResult"] = "result[0] != result[0]", ["ValidateRemainingResults"] = "result[i] != ((i == 0) ? result[i] : 0)"}), + ("SimpleUnOpTest.template", new Dictionary { ["Isa"] = "Avx10v2", ["LoadIsa"] = "Avx10v1", ["Method"] = "MoveScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateFirstResult"] = "result[0] != result[0]", ["ValidateRemainingResults"] = "result[i] != ((i == 0) ? result[i] : 0)"}), + ("SimpleUnOpTest.template", new Dictionary { ["Isa"] = "Avx10v2", ["LoadIsa"] = "Avx10v1", ["Method"] = "MoveScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateFirstResult"] = "result[0] != result[0]", ["ValidateRemainingResults"] = "result[i] != ((i == 0) ? result[i] : 0)"}), + ("SimpleUnOpTest.template", new Dictionary { ["Isa"] = "Avx10v2", ["LoadIsa"] = "Avx10v1", ["Method"] = "MoveScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateFirstResult"] = "result[0] != result[0]", ["ValidateRemainingResults"] = "result[i] != ((i == 0) ? result[i] : 0)"}), ("SimpleBinOpEmbRounding.template", new Dictionary { ["Isa"] = "Avx10v2", ["LoadIsa"] = "Avx10v1", ["Method"] = "Add", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Double", ["RoundingMode"] = "ToNegativeInfinity", ["CastingMethod"] = "DoubleToUInt64Bits", ["FixedInput1"] = "0.05", ["FixedInput2"] = "0.45", ["LargestVectorSize"] = "32"}), ("SimpleBinOpEmbRounding.template", new Dictionary { ["Isa"] = "Avx10v2", ["LoadIsa"] = "Avx10v1", ["Method"] = "Add", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Double", ["RoundingMode"] = "ToPositiveInfinity", ["CastingMethod"] = "DoubleToUInt64Bits", ["FixedInput1"] = "0.05", ["FixedInput2"] = "0.45", ["LargestVectorSize"] = "32"}), ("SimpleBinOpEmbRounding.template", new Dictionary { ["Isa"] = "Avx10v2", ["LoadIsa"] = "Avx10v1", ["Method"] = "Add", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Double", ["RoundingMode"] = "ToZero", ["CastingMethod"] = "DoubleToUInt64Bits", ["FixedInput1"] = "0.05", ["FixedInput2"] = "0.45", ["LargestVectorSize"] = "32"}), @@ -1889,6 +1893,8 @@ ("SimpleUnaryOpEmbRounding.template", new Dictionary { ["Isa"] = "Avx10v2", ["LoadIsa"] = "Avx10v1", ["Method"] = "Sqrt", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Single", ["RoundingMode"] = "ToNegativeInfinity", ["CastingMethod"] = "BitConverter.SingleToUInt32Bits", ["FixedInput"] = "29.37", ["LargestVectorSize"] = "32"}), ("SimpleUnaryOpEmbRounding.template", new Dictionary { ["Isa"] = "Avx10v2", ["LoadIsa"] = "Avx10v1", ["Method"] = "Sqrt", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Single", ["RoundingMode"] = "ToPositiveInfinity", ["CastingMethod"] = "BitConverter.SingleToUInt32Bits", ["FixedInput"] = "29.37", ["LargestVectorSize"] = "32"}), ("SimpleUnaryOpEmbRounding.template", new Dictionary { ["Isa"] = "Avx10v2", ["LoadIsa"] = "Avx10v1", ["Method"] = "Sqrt", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Single", ["RoundingMode"] = "ToZero", ["CastingMethod"] = "BitConverter.SingleToUInt32Bits", ["FixedInput"] = "29.37", ["LargestVectorSize"] = "32"}), + ("StoreUnOpTest.template", new Dictionary { ["Isa"] = "Avx10v2", ["LoadIsa"] = "Avx10v1", ["Method"] = "StoreScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateFirstResult"] = "value[0] != result[0]", ["ValidateRemainingResults"] = "0 != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["Isa"] = "Avx10v2", ["LoadIsa"] = "Avx10v1", ["Method"] = "StoreScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateFirstResult"] = "value[0] != result[0]", ["ValidateRemainingResults"] = "0 != result[i]"}), ("SimpleBinOpEmbRounding.template", new Dictionary { ["Isa"] = "Avx10v2", ["LoadIsa"] = "Avx10v1", ["Method"] = "Subtract", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Double", ["RoundingMode"] = "ToNegativeInfinity", ["CastingMethod"] = "DoubleToUInt64Bits", ["FixedInput1"] = "0.05", ["FixedInput2"] = "0.45", ["LargestVectorSize"] = "32"}), ("SimpleBinOpEmbRounding.template", new Dictionary { ["Isa"] = "Avx10v2", ["LoadIsa"] = "Avx10v1", ["Method"] = "Subtract", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Double", ["RoundingMode"] = "ToPositiveInfinity", ["CastingMethod"] = "DoubleToUInt64Bits", ["FixedInput1"] = "0.05", ["FixedInput2"] = "0.45", ["LargestVectorSize"] = "32"}), ("SimpleBinOpEmbRounding.template", new Dictionary { ["Isa"] = "Avx10v2", ["LoadIsa"] = "Avx10v1", ["Method"] = "Subtract", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Double", ["RoundingMode"] = "ToZero", ["CastingMethod"] = "DoubleToUInt64Bits", ["FixedInput1"] = "0.05", ["FixedInput2"] = "0.45", ["LargestVectorSize"] = "32"}), diff --git a/src/runtime/src/tests/JIT/HardwareIntrinsics/X86_Avx10v2/Avx10v2/Avx10v2SampleTest.cs b/src/runtime/src/tests/JIT/HardwareIntrinsics/X86_Avx10v2/Avx10v2/Avx10v2SampleTest.cs index 15bc0c4b844..670b572594a 100644 --- a/src/runtime/src/tests/JIT/HardwareIntrinsics/X86_Avx10v2/Avx10v2/Avx10v2SampleTest.cs +++ b/src/runtime/src/tests/JIT/HardwareIntrinsics/X86_Avx10v2/Avx10v2/Avx10v2SampleTest.cs @@ -62,25 +62,8 @@ public static unsafe void Avx10v2SampleTest () if (Avx10v2.IsSupported) { Console.WriteLine("Avx10v2 supported"); - Vector128 val = Vector128.Create(-5); - Vector128 absVal = getAbs128(val); - Vector128 left = Vector128.Create(11.0); - Vector128 right = Vector128.Create(-12.0); - Vector128 firstOp = Vector128.Create(0.65f); - Vector256 secondOp = Vector256.Create(27.35f); - // Console.WriteLine("widen to int is " + Avx10v2.ConvertToByteWithSaturationAndWidenToInt32(secondOp, FloatRoundingMode.ToNegativeInfinity)); - // Console.WriteLine("widen to int is " + Avx10v2.ConvertToByteWithSaturationAndWidenToInt32(secondOp, FloatRoundingMode.ToPositiveInfinity)); - // Console.WriteLine("widen to int is " + Avx10v2.ConvertToByteWithSaturationAndWidenToInt32(secondOp, FloatRoundingMode.ToZero)); - // Console.WriteLine("Scalar conversion " + (int)(sbyte)Math.Clamp(Math.Round(0.65f), sbyte.MinValue, sbyte.MaxValue)); - // Console.WriteLine("widen to uint is " + Avx10v2.ConvertToByteWithSaturationAndWidenToInt32(firstOp)); - // Console.WriteLine("widen to int is " + Avx10v2.ConvertToSByteWithSaturationAndWidenToInt32(secondOp)); - // Console.WriteLine("widen to uint is " + Avx10v2.ConvertToByteWithSaturationAndWidenToInt32(secondOp)); - // Console.WriteLine("widen trunc to int is " + Avx10v2.ConvertToByteWithTruncationSaturationAndWidenToInt32(firstOp)); - // Console.WriteLine("widen trunc to uint is " + Avx10v2.ConvertToSByteWithTruncationSaturationAndWidenToInt32(firstOp)); - // Console.WriteLine("widen trunc to int is " + Avx10v2.ConvertToByteWithTruncationSaturationAndWidenToInt32(secondOp)); - // Console.WriteLine("widen trunc to uint is " + Avx10v2.ConvertToSByteWithTruncationSaturationAndWidenToInt32(secondOp)); - // Console.WriteLine("MinMax is " + Avx10v2.MinMax(left, right, 0x00)); - // Console.WriteLine("MinMax is " + Avx10v2.MinMax(left, right, 0x04)); + Vector128 val = Vector128.Create((int)8); + Console.WriteLine("Moving Scalar: " + Avx10v2.MoveScalar(val)); } else { Console.WriteLine("Avx10v2 not supported"); diff --git a/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_114978/Runtime_114978.cs b/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_114978/Runtime_114978.cs new file mode 100644 index 00000000000..d9d150f7b9a --- /dev/null +++ b/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_114978/Runtime_114978.cs @@ -0,0 +1,76 @@ +// Generated by Fuzzlyn v2.7 on 2025-04-23 21:44:41 +// Run on X64 Windows +// Seed: 3309115426102150651-vectort,vector128,vector256,vector512,x86aes,x86avx,x86avx2,x86avx512bw,x86avx512bwvl,x86avx512cd,x86avx512cdvl,x86avx512dq,x86avx512dqvl,x86avx512f,x86avx512fvl,x86avx512fx64,x86avx512vbmi,x86avx512vbmivl,x86bmi1,x86bmi1x64,x86bmi2,x86bmi2x64,x86fma,x86lzcnt,x86lzcntx64,x86pclmulqdq,x86popcnt,x86popcntx64,x86sse,x86ssex64,x86sse2,x86sse2x64,x86sse3,x86sse41,x86sse41x64,x86sse42,x86sse42x64,x86ssse3,x86x86base +// Reduced from 179.3 KiB to 1.4 KiB in 00:01:49 +// Debug: Outputs <255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255> +// Release: Outputs <255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0> + +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +using Xunit; + +public class C0 +{ +} + +public class C1 +{ + public Vector512 F4; +} + +public class C2 +{ + public Vector128 F6; +} + +public class Runtime_114978 +{ + public static IRuntime s_rt; + + [Fact] + public static void Problem() + { + if (Avx512BW.VL.IsSupported) + { + s_rt = new Runtime(); + var vr14 = new C1(); + var vr16 = new C1(); + var vr17 = (byte)0; + var vr18 = Vector512.CreateScalar(vr17); + var vr19 = new C2(); + var vr20 = new C0(); + var vr21 = M10(vr14, vr18, vr19, vr20); + s_rt.AssertEqual(Vector512.AllBitsSet, vr21); + var vr22 = new C2(); + var vr23 = new C0(); + var vr24 = M10(vr16, vr21, vr22, vr23); + s_rt.AssertEqual(Vector512.AllBitsSet, vr24); + } + } + + public static Vector512 M10(C1 argThis, Vector512 arg0, C2 arg1, C0 arg2) + { + var vr3 = arg1.F6; + var vr6 = arg1.F6; + var vr0 = Avx512BW.VL.CompareLessThanOrEqual(vr3, vr6); + var vr10 = (sbyte)1; + var vr9 = Vector128.CreateScalar(vr10); + if (Sse41.TestZ(vr0, vr9)) + { + s_rt.AssertEqual(Vector512.Zero, argThis.F4); + } + + return Avx512BW.CompareEqual(arg0, arg0); + } +} + +public interface IRuntime +{ + void AssertEqual(Vector512 value1, Vector512 value2); +} + +public class Runtime : IRuntime +{ + public void AssertEqual(Vector512 value1, Vector512 value2) + => Assert.Equal(value1, value2); +} \ No newline at end of file diff --git a/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_114978/Runtime_114978.csproj b/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_114978/Runtime_114978.csproj new file mode 100644 index 00000000000..de6d5e08882 --- /dev/null +++ b/src/runtime/src/tests/JIT/Regression/JitBlue/Runtime_114978/Runtime_114978.csproj @@ -0,0 +1,8 @@ + + + True + + + + + diff --git a/src/scenario-tests/azure-pipelines.yml b/src/scenario-tests/azure-pipelines.yml index ca03fd5d6aa..929fe182297 100644 --- a/src/scenario-tests/azure-pipelines.yml +++ b/src/scenario-tests/azure-pipelines.yml @@ -41,8 +41,4 @@ extends: jobs: - template: /eng/common/templates-official/jobs/jobs.yml@self parameters: - artifacts: - publish: - manifests: true isAssetlessBuild: true - publishAssetsImmediately: true diff --git a/src/scenario-tests/eng/Version.Details.xml b/src/scenario-tests/eng/Version.Details.xml index ff03f650c6d..e6da428ce41 100644 --- a/src/scenario-tests/eng/Version.Details.xml +++ b/src/scenario-tests/eng/Version.Details.xml @@ -1,16 +1,16 @@ - + - + https://github.com/dotnet/dotnet - 5fd0935290d20e7172918595a509a367df7d5bb6 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 5fd0935290d20e7172918595a509a367df7d5bb6 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 diff --git a/src/scenario-tests/eng/Versions.props b/src/scenario-tests/eng/Versions.props index 8850be53783..ddf3519eab1 100644 --- a/src/scenario-tests/eng/Versions.props +++ b/src/scenario-tests/eng/Versions.props @@ -4,6 +4,6 @@ preview - 2.0.0-beta5.25228.101 + 2.0.0-beta5.25251.105 diff --git a/src/scenario-tests/eng/common/core-templates/jobs/source-build.yml b/src/scenario-tests/eng/common/core-templates/jobs/source-build.yml index a10ccfbee6d..df24c948ba1 100644 --- a/src/scenario-tests/eng/common/core-templates/jobs/source-build.yml +++ b/src/scenario-tests/eng/common/core-templates/jobs/source-build.yml @@ -14,7 +14,7 @@ parameters: # This is the default platform provided by Arcade, intended for use by a managed-only repo. defaultManagedPlatform: name: 'Managed' - container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream9' + container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream-10-amd64' # Defines the platforms on which to run build jobs. One job is created for each platform, and the # object in this array is sent to the job template as 'platform'. If no platforms are specified, diff --git a/src/scenario-tests/eng/common/core-templates/steps/source-build.yml b/src/scenario-tests/eng/common/core-templates/steps/source-build.yml index 8c88ccd7b08..c6b9ef51ac6 100644 --- a/src/scenario-tests/eng/common/core-templates/steps/source-build.yml +++ b/src/scenario-tests/eng/common/core-templates/steps/source-build.yml @@ -121,14 +121,3 @@ steps: continueOnError: true condition: succeededOrFailed() sbomEnabled: false # we don't need SBOM for logs - -# Manually inject component detection so that we can ignore the source build upstream cache, which contains -# a nupkg cache of input packages (a local feed). -# This path must match the upstream cache path in property 'CurrentRepoSourceBuiltNupkgCacheDir' -# in src\Microsoft.DotNet.Arcade.Sdk\tools\SourceBuild\SourceBuildArcade.targets -- template: /eng/common/core-templates/steps/component-governance.yml - parameters: - displayName: Component Detection (Exclude upstream cache) - is1ESPipeline: ${{ parameters.is1ESPipeline }} - componentGovernanceIgnoreDirectories: '$(Build.SourcesDirectory)/artifacts/sb/src/artifacts/obj/source-built-upstream-cache' - disableComponentGovernance: ${{ eq(variables['System.TeamProject'], 'public') }} diff --git a/src/scenario-tests/global.json b/src/scenario-tests/global.json index ad7ab9c3170..817ac8ef234 100644 --- a/src/scenario-tests/global.json +++ b/src/scenario-tests/global.json @@ -10,6 +10,6 @@ } }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25228.101" + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25251.105" } } diff --git a/src/sdk/eng/Version.Details.xml b/src/sdk/eng/Version.Details.xml index 3aebf864b37..a643ef08dfb 100644 --- a/src/sdk/eng/Version.Details.xml +++ b/src/sdk/eng/Version.Details.xml @@ -133,74 +133,74 @@ https://github.com/dotnet/dotnet 35ccf19f39389d127ab037709b8e9c5a1b111a20 - + https://github.com/nuget/nuget.client - 86c695c5bdd02ca0aa735eed42508b57f695baa7 + 41fb88a624e61dce1fa05a5d0771b41ab7aff7a9 - + https://github.com/nuget/nuget.client - 86c695c5bdd02ca0aa735eed42508b57f695baa7 + 41fb88a624e61dce1fa05a5d0771b41ab7aff7a9 - + https://github.com/nuget/nuget.client - 86c695c5bdd02ca0aa735eed42508b57f695baa7 + 41fb88a624e61dce1fa05a5d0771b41ab7aff7a9 - + https://github.com/nuget/nuget.client - 86c695c5bdd02ca0aa735eed42508b57f695baa7 + 41fb88a624e61dce1fa05a5d0771b41ab7aff7a9 - + https://github.com/nuget/nuget.client - 86c695c5bdd02ca0aa735eed42508b57f695baa7 + 41fb88a624e61dce1fa05a5d0771b41ab7aff7a9 - + https://github.com/nuget/nuget.client - 86c695c5bdd02ca0aa735eed42508b57f695baa7 + 41fb88a624e61dce1fa05a5d0771b41ab7aff7a9 - + https://github.com/nuget/nuget.client - 86c695c5bdd02ca0aa735eed42508b57f695baa7 + 41fb88a624e61dce1fa05a5d0771b41ab7aff7a9 - + https://github.com/nuget/nuget.client - 86c695c5bdd02ca0aa735eed42508b57f695baa7 + 41fb88a624e61dce1fa05a5d0771b41ab7aff7a9 - + https://github.com/nuget/nuget.client - 86c695c5bdd02ca0aa735eed42508b57f695baa7 + 41fb88a624e61dce1fa05a5d0771b41ab7aff7a9 - + https://github.com/nuget/nuget.client - 86c695c5bdd02ca0aa735eed42508b57f695baa7 + 41fb88a624e61dce1fa05a5d0771b41ab7aff7a9 - + https://github.com/nuget/nuget.client - 86c695c5bdd02ca0aa735eed42508b57f695baa7 + 41fb88a624e61dce1fa05a5d0771b41ab7aff7a9 - + https://github.com/nuget/nuget.client - 86c695c5bdd02ca0aa735eed42508b57f695baa7 + 41fb88a624e61dce1fa05a5d0771b41ab7aff7a9 - + https://github.com/nuget/nuget.client - 86c695c5bdd02ca0aa735eed42508b57f695baa7 + 41fb88a624e61dce1fa05a5d0771b41ab7aff7a9 - + https://github.com/nuget/nuget.client - 86c695c5bdd02ca0aa735eed42508b57f695baa7 + 41fb88a624e61dce1fa05a5d0771b41ab7aff7a9 - + https://github.com/nuget/nuget.client - 86c695c5bdd02ca0aa735eed42508b57f695baa7 + 41fb88a624e61dce1fa05a5d0771b41ab7aff7a9 - + https://github.com/nuget/nuget.client - 86c695c5bdd02ca0aa735eed42508b57f695baa7 + 41fb88a624e61dce1fa05a5d0771b41ab7aff7a9 - + https://github.com/nuget/nuget.client - 86c695c5bdd02ca0aa735eed42508b57f695baa7 + 41fb88a624e61dce1fa05a5d0771b41ab7aff7a9 https://github.com/dotnet/dotnet diff --git a/src/sdk/eng/Versions.props b/src/sdk/eng/Versions.props index 5ac2774d20f..ebc30c080d1 100644 --- a/src/sdk/eng/Versions.props +++ b/src/sdk/eng/Versions.props @@ -161,18 +161,18 @@ - 6.15.0-preview.1.31 - 6.15.0-preview.1.31 - 6.15.0-preview.1.31 - 6.15.0-preview.1.31 - 6.15.0-preview.1.31 - 6.15.0-preview.1.31 - 6.15.0-preview.1.31 - 6.15.0-preview.1.31 - 6.15.0-preview.1.31 - 6.15.0-preview.1.31 - 6.15.0-preview.1.31 - 6.15.0-preview.1.31 + 6.15.0-preview.1.37 + 6.15.0-preview.1.37 + 6.15.0-preview.1.37 + 6.15.0-preview.1.37 + 6.15.0-preview.1.37 + 6.15.0-preview.1.37 + 6.15.0-preview.1.37 + 6.15.0-preview.1.37 + 6.15.0-preview.1.37 + 6.15.0-preview.1.37 + 6.15.0-preview.1.37 + 6.15.0-preview.1.37 diff --git a/src/sdk/sdk.sln b/src/sdk/sdk.sln index 78ffd859f27..43de36ddd32 100644 --- a/src/sdk/sdk.sln +++ b/src/sdk/sdk.sln @@ -1045,6 +1045,7 @@ Global {4F23A9C8-945A-A4F4-51E9-FCA215943C0D}.Debug|Any CPU.Build.0 = Debug|Any CPU {4F23A9C8-945A-A4F4-51E9-FCA215943C0D}.Release|Any CPU.ActiveCfg = Release|Any CPU {4F23A9C8-945A-A4F4-51E9-FCA215943C0D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection diff --git a/src/sdk/src/Cli/dotnet/Commands/Solution/Add/SolutionAddCommand.cs b/src/sdk/src/Cli/dotnet/Commands/Solution/Add/SolutionAddCommand.cs index 66db2e71cde..137ec586119 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Solution/Add/SolutionAddCommand.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Solution/Add/SolutionAddCommand.cs @@ -15,12 +15,11 @@ namespace Microsoft.DotNet.Cli.Commands.Solution.Add; internal class SolutionAddCommand : CommandBase { - private static readonly string[] _defaultPlatforms = ["Any CPU", "x64", "x86"]; - private static readonly string[] _defaultBuildTypes = ["Debug", "Release"]; private readonly string _fileOrDirectory; private readonly bool _inRoot; private readonly IReadOnlyCollection _projects; private readonly string? _solutionFolderPath; + private string _solutionFileFullPath = string.Empty; private static string GetSolutionFolderPathWithForwardSlashes(string path) { @@ -29,6 +28,13 @@ private static string GetSolutionFolderPathWithForwardSlashes(string path) return "/" + string.Join("/", PathUtility.GetPathWithDirectorySeparator(path).Split(Path.DirectorySeparatorChar, StringSplitOptions.RemoveEmptyEntries)) + "/"; } + private static bool IsSolutionFolderPathInDirectoryScope(string relativePath) + { + return !string.IsNullOrWhiteSpace(relativePath) + && !Path.IsPathRooted(relativePath) // This means path is in a different volume + && !relativePath.StartsWith(".."); // This means path is outside the solution directory + } + public SolutionAddCommand(ParseResult parseResult) : base(parseResult) { _fileOrDirectory = parseResult.GetValue(SolutionCommandParser.SlnArgument); @@ -36,6 +42,7 @@ public SolutionAddCommand(ParseResult parseResult) : base(parseResult) _inRoot = parseResult.GetValue(SolutionAddCommandParser.InRootOption); _solutionFolderPath = parseResult.GetValue(SolutionAddCommandParser.SolutionFolderOption); SolutionArgumentValidator.ParseAndValidateArguments(_fileOrDirectory, _projects, SolutionArgumentValidator.CommandType.Add, _inRoot, _solutionFolderPath); + _solutionFileFullPath = SlnFileFactory.GetSolutionFileFullPath(_fileOrDirectory); } public override int Execute() @@ -44,35 +51,63 @@ public override int Execute() { throw new GracefulException(CliStrings.SpecifyAtLeastOneProjectToAdd); } - string solutionFileFullPath = SlnFileFactory.GetSolutionFileFullPath(_fileOrDirectory); - try + // Get project paths from the command line arguments + PathUtility.EnsureAllPathsExist(_projects, CliStrings.CouldNotFindProjectOrDirectory, true); + + IEnumerable fullProjectPaths = _projects.Select(project => { - PathUtility.EnsureAllPathsExist(_projects, CliStrings.CouldNotFindProjectOrDirectory, true); - IEnumerable fullProjectPaths = _projects.Select(project => - { - var fullPath = Path.GetFullPath(project); - return Directory.Exists(fullPath) ? MsbuildProject.GetProjectFileFromDirectory(fullPath).FullName : fullPath; - }); - AddProjectsToSolutionAsync(solutionFileFullPath, fullProjectPaths, CancellationToken.None).GetAwaiter().GetResult(); - return 0; + var fullPath = Path.GetFullPath(project); + return Directory.Exists(fullPath) ? MsbuildProject.GetProjectFileFromDirectory(fullPath).FullName : fullPath; + }); + + // Add projects to the solution + AddProjectsToSolutionAsync(fullProjectPaths, CancellationToken.None).GetAwaiter().GetResult(); + return 0; + } + + private SolutionFolderModel? GenerateIntermediateSolutionFoldersForProjectPath(SolutionModel solution, string relativeProjectPath) + { + if (_inRoot) + { + return null; } - catch (Exception ex) when (ex is not GracefulException) + + string relativeSolutionFolderPath = string.Empty; + + if (string.IsNullOrEmpty(_solutionFolderPath)) { + // Generate the solution folder path based on the project path + relativeSolutionFolderPath = Path.GetDirectoryName(relativeProjectPath); + + // If the project is in a folder with the same name as the project, we need to go up one level + if (relativeSolutionFolderPath.Split(Path.DirectorySeparatorChar).LastOrDefault() == Path.GetFileNameWithoutExtension(relativeProjectPath)) + { + relativeSolutionFolderPath = Path.Combine([.. relativeSolutionFolderPath.Split(Path.DirectorySeparatorChar).SkipLast(1)]); + } + + // If the generated path is outside the solution directory, we need to set it to empty + if (!IsSolutionFolderPathInDirectoryScope(relativeSolutionFolderPath)) { - if (ex is SolutionException || ex.InnerException is SolutionException) - { - throw new GracefulException(CliStrings.InvalidSolutionFormatString, solutionFileFullPath, ex.Message); - } - throw new GracefulException(ex.Message, ex); + relativeSolutionFolderPath = string.Empty; } } + else + { + // Use the provided solution folder path + relativeSolutionFolderPath = _solutionFolderPath; + } + + return string.IsNullOrEmpty(relativeSolutionFolderPath) + ? null + : solution.AddFolder(GetSolutionFolderPathWithForwardSlashes(relativeSolutionFolderPath)); } - private async Task AddProjectsToSolutionAsync(string solutionFileFullPath, IEnumerable projectPaths, CancellationToken cancellationToken) + private async Task AddProjectsToSolutionAsync(IEnumerable projectPaths, CancellationToken cancellationToken) { - SolutionModel solution = SlnFileFactory.CreateFromFileOrDirectory(solutionFileFullPath); + SolutionModel solution = SlnFileFactory.CreateFromFileOrDirectory(_solutionFileFullPath); ISolutionSerializer serializer = solution.SerializerExtension.Serializer; + // set UTF8 BOM encoding for .sln if (serializer is ISolutionSerializer v12Serializer) { @@ -80,79 +115,71 @@ private async Task AddProjectsToSolutionAsync(string solutionFileFullPath, IEnum { Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: true) }); + // Set default configurations and platforms for sln file - foreach (var platform in _defaultPlatforms) + foreach (var platform in SlnFileFactory.DefaultPlatforms) { solution.AddPlatform(platform); } - foreach (var buildType in _defaultBuildTypes) + + foreach (var buildType in SlnFileFactory.DefaultBuildTypes) { solution.AddBuildType(buildType); } } - SolutionFolderModel? solutionFolder = !_inRoot && !string.IsNullOrEmpty(_solutionFolderPath) - ? solution.AddFolder(GetSolutionFolderPathWithForwardSlashes(_solutionFolderPath)) - : null; - foreach (var projectPath in projectPaths) { - string relativePath = Path.GetRelativePath(Path.GetDirectoryName(solutionFileFullPath), projectPath); - // Add fallback solution folder if relative path does not contain `..`. - string relativeSolutionFolder = relativePath.Split(Path.DirectorySeparatorChar).Any(p => p == "..") - ? string.Empty : Path.GetDirectoryName(relativePath); - - if (!_inRoot && solutionFolder is null && !string.IsNullOrEmpty(relativeSolutionFolder)) - { - if (relativeSolutionFolder.Split(Path.DirectorySeparatorChar).LastOrDefault() == Path.GetFileNameWithoutExtension(relativePath)) - { - relativeSolutionFolder = Path.Combine([.. relativeSolutionFolder.Split(Path.DirectorySeparatorChar).SkipLast(1)]); - } - if (!string.IsNullOrEmpty(relativeSolutionFolder)) - { - solutionFolder = solution.AddFolder(GetSolutionFolderPathWithForwardSlashes(relativeSolutionFolder)); - } - } - - try - { - AddProject(solution, relativePath, projectPath, solutionFolder, serializer); - } - catch (InvalidProjectFileException ex) - { - Reporter.Error.WriteLine(string.Format(CliStrings.InvalidProjectWithExceptionMessage, projectPath, ex.Message)); - } - catch (SolutionArgumentException ex) when (solution.FindProject(relativePath) != null || ex.Type == SolutionErrorType.DuplicateProjectName) - { - Reporter.Output.WriteLine(CliStrings.SolutionAlreadyContainsProject, solutionFileFullPath, relativePath); - } + AddProject(solution, projectPath, serializer); } - await serializer.SaveAsync(solutionFileFullPath, solution, cancellationToken); + + await serializer.SaveAsync(_solutionFileFullPath, solution, cancellationToken); } - private static void AddProject(SolutionModel solution, string solutionRelativeProjectPath, string fullPath, SolutionFolderModel? solutionFolder, ISolutionSerializer serializer = null) + private void AddProject(SolutionModel solution, string fullProjectPath, ISolutionSerializer serializer = null) { + string solutionRelativeProjectPath = Path.GetRelativePath(Path.GetDirectoryName(_solutionFileFullPath), fullProjectPath); + // Open project instance to see if it is a valid project - ProjectRootElement projectRootElement = ProjectRootElement.Open(fullPath); + ProjectRootElement projectRootElement; + try + { + projectRootElement = ProjectRootElement.Open(fullProjectPath); + } + catch (InvalidProjectFileException ex) + { + Reporter.Error.WriteLine(string.Format(CliStrings.InvalidProjectWithExceptionMessage, fullProjectPath, ex.Message)); + return; + } + ProjectInstance projectInstance = new ProjectInstance(projectRootElement); + + string projectTypeGuid = solution.ProjectTypes.FirstOrDefault(t => t.Extension == Path.GetExtension(fullProjectPath))?.ProjectTypeId.ToString() + ?? projectRootElement.GetProjectTypeGuid() ?? projectInstance.GetDefaultProjectTypeGuid(); + + // Generate the solution folder path based on the project path + SolutionFolderModel? solutionFolder = GenerateIntermediateSolutionFoldersForProjectPath(solution, solutionRelativeProjectPath); + SolutionProjectModel project; + try { - project = solution.AddProject(solutionRelativeProjectPath, null, solutionFolder); + project = solution.AddProject(solutionRelativeProjectPath, projectTypeGuid, solutionFolder); } - catch (SolutionArgumentException ex) when (ex.ParamName == "projectTypeName") + catch (SolutionArgumentException ex) when (ex.Type == SolutionErrorType.InvalidProjectTypeReference) { - // If guid is not identified by vs-solutionpersistence, check in project element itself - var guid = projectRootElement.GetProjectTypeGuid() ?? projectInstance.GetDefaultProjectTypeGuid(); - if (string.IsNullOrEmpty(guid)) - { - Reporter.Error.WriteLine(CliStrings.UnsupportedProjectType, fullPath); - return; - } - project = solution.AddProject(solutionRelativeProjectPath, guid, solutionFolder); + Reporter.Error.WriteLine(CliStrings.UnsupportedProjectType, fullProjectPath); + return; + } + catch (SolutionArgumentException ex) when (ex.Type == SolutionErrorType.DuplicateProjectName || solution.FindProject(solutionRelativeProjectPath) is not null) + { + Reporter.Output.WriteLine(CliStrings.SolutionAlreadyContainsProject, _solutionFileFullPath, solutionRelativeProjectPath); + return; } + // Add settings based on existing project instance string projectInstanceId = projectInstance.GetProjectId(); + if (!string.IsNullOrEmpty(projectInstanceId) && serializer is ISolutionSerializer) { project.Id = new Guid(projectInstanceId); @@ -164,7 +191,7 @@ private static void AddProject(SolutionModel solution, string solutionRelativePr foreach (var solutionPlatform in solution.Platforms) { var projectPlatform = projectInstancePlatforms.FirstOrDefault( - platform => platform.Replace(" ", string.Empty) == solutionPlatform.Replace(" ", string.Empty), projectInstancePlatforms.FirstOrDefault()); + platform => platform.Replace(" ", string.Empty) == solutionPlatform.Replace(" ", string.Empty), projectInstancePlatforms.FirstOrDefault()); project.AddProjectConfigurationRule(new ConfigurationRule(BuildDimension.Platform, "*", solutionPlatform, projectPlatform)); } @@ -174,6 +201,7 @@ private static void AddProject(SolutionModel solution, string solutionRelativePr buildType => buildType.Replace(" ", string.Empty) == solutionBuildType.Replace(" ", string.Empty), projectInstanceBuildTypes.FirstOrDefault()); project.AddProjectConfigurationRule(new ConfigurationRule(BuildDimension.BuildType, solutionBuildType, "*", projectBuildType)); } + Reporter.Output.WriteLine(CliStrings.ProjectAddedToTheSolution, solutionRelativeProjectPath); } } diff --git a/src/sdk/src/Cli/dotnet/Commands/Test/Terminal/TerminalTestReporter.cs b/src/sdk/src/Cli/dotnet/Commands/Test/Terminal/TerminalTestReporter.cs index 8944e229a76..41bd37ba508 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Test/Terminal/TerminalTestReporter.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Test/Terminal/TerminalTestReporter.cs @@ -159,30 +159,15 @@ public void TestExecutionStarted(DateTimeOffset testStartTime, int workerCount, _terminalWithProgress.StartShowingProgress(workerCount); } - public void AssemblyRunStarted(string assembly, string? targetFramework, string? architecture, string? executionId, string? instanceId) + public void AssemblyRunStarted(string assembly, string? targetFramework, string? architecture, string? executionId) { var assemblyRun = GetOrAddAssemblyRun(assembly, targetFramework, architecture, executionId); - assemblyRun.Tries.Add(instanceId); + assemblyRun.TryCount++; // If we fail to parse out the parameter correctly this will enable retry on re-run of the assembly within the same execution. // Not good enough for general use, because we want to show (try 1) even on the first try, but this will at // least show (try 2) etc. So user is still aware there is retry going on, and counts of tests won't break. - _isRetry |= assemblyRun.Tries.Count > 1; - - if (_isRetry) - { - // When we are retrying the new assembly run should ignore all previously failed tests and - // clear all errors. We restarted the run and will retry all failed tests. - // - // In case of folded dynamic data tests we do not know how many tests we will get in each run, - // if more or less, or the same amount as before,and we also will rerun tests that passed previously - // because we are unable to run just a single test from that dynamic data source. - // This will cause the total number of tests to differ between runs, and there is nothing we can do about it. - assemblyRun.TotalTests -= assemblyRun.FailedTests; - assemblyRun.RetriedFailedTests += assemblyRun.FailedTests; - assemblyRun.FailedTests = 0; - assemblyRun.ClearAllMessages(); - } + _isRetry |= assemblyRun.TryCount > 1; if (_options.ShowAssembly && _options.ShowAssemblyStartAndComplete) { @@ -191,7 +176,7 @@ public void AssemblyRunStarted(string assembly, string? targetFramework, string? if (_isRetry) { terminal.SetColor(TerminalColor.DarkGray); - terminal.Append($"({string.Format(CliCommandStrings.Try, assemblyRun.Tries.Count)}) "); + terminal.Append($"({string.Format(CliCommandStrings.Try, assemblyRun.TryCount)}) "); terminal.ResetColor(); } @@ -480,7 +465,7 @@ internal void TestCompleted( string? errorOutput) { TestProgressState asm = _assemblies[$"{assembly}|{targetFramework}|{architecture}|{executionId}"]; - var attempt = asm.Tries.Count; + var attempt = asm.TryCount; if (_options.ShowActiveTests) { @@ -493,20 +478,17 @@ internal void TestCompleted( case TestOutcome.Timeout: case TestOutcome.Canceled: case TestOutcome.Fail: - asm.FailedTests++; - asm.TotalTests++; + asm.ReportFailedTest(testNodeUid, instanceId); break; case TestOutcome.Passed: - asm.PassedTests++; - asm.TotalTests++; + asm.ReportPassingTest(testNodeUid, instanceId); break; case TestOutcome.Skipped: - asm.SkippedTests++; - asm.TotalTests++; + asm.ReportSkippedTest(testNodeUid, instanceId); break; } - if (_isRetry && asm.Tries.Count > 1 && outcome == TestOutcome.Passed) + if (_isRetry && asm.TryCount > 1 && outcome == TestOutcome.Passed) { // This is a retry of a test, and the test succeeded, so these tests are potentially flaky. // Tests that come from dynamic data sources and previously succeeded will also run on the second attempt, @@ -904,50 +886,6 @@ public void StartCancelling() }); } - internal void WriteErrorMessage(string assembly, string? targetFramework, string? architecture, string? executionId, string text, int? padding) - { - TestProgressState asm = GetOrAddAssemblyRun(assembly, targetFramework, architecture, executionId); - asm.AddError(text); - - _terminalWithProgress.WriteToTerminal(terminal => - { - terminal.SetColor(TerminalColor.Red); - if (padding == null) - { - terminal.AppendLine(text); - } - else - { - AppendIndentedLine(terminal, text, new string(' ', padding.Value)); - } - - terminal.ResetColor(); - }); - } - - internal void WriteWarningMessage(string assembly, string? targetFramework, string? architecture, string? executionId, string text, int? padding) - { - TestProgressState asm = GetOrAddAssemblyRun(assembly, targetFramework, architecture, executionId); - asm.AddWarning(text); - _terminalWithProgress.WriteToTerminal(terminal => - { - terminal.SetColor(TerminalColor.Yellow); - if (padding == null) - { - terminal.AppendLine(text); - } - else - { - AppendIndentedLine(terminal, text, new string(' ', padding.Value)); - } - - terminal.ResetColor(); - }); - } - - internal void WriteErrorMessage(string assembly, string? targetFramework, string? architecture, string? executionId, Exception exception) - => WriteErrorMessage(assembly, targetFramework, architecture, executionId, exception.ToString(), padding: null); - public void WriteMessage(string text, SystemConsoleColor? color = null, int? padding = null) { if (color != null) @@ -994,9 +932,7 @@ internal void TestDiscovered( TestProgressState asm = _assemblies[$"{assembly}|{targetFramework}|{architecture}|{executionId}"]; // TODO: add mode for discovered tests to the progress bar - jajares - asm.PassedTests++; - asm.TotalTests++; - asm.DiscoveredTests.Add(new(displayName, uid)); + asm.DiscoverTest(displayName, uid); _terminalWithProgress.UpdateWorker(asm.SlotIndex); } diff --git a/src/sdk/src/Cli/dotnet/Commands/Test/Terminal/TestProgressState.cs b/src/sdk/src/Cli/dotnet/Commands/Test/Terminal/TestProgressState.cs index 72ce503d10d..0c31239a94e 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Test/Terminal/TestProgressState.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Test/Terminal/TestProgressState.cs @@ -5,6 +5,8 @@ namespace Microsoft.DotNet.Cli.Commands.Test.Terminal; internal sealed class TestProgressState(long id, string assembly, string? targetFramework, string? architecture, IStopwatch stopwatch) { + private readonly Dictionary _testUidToResults = new(); + public string Assembly { get; } = assembly; public string AssemblyName { get; } = Path.GetFileName(assembly)!; @@ -15,19 +17,15 @@ internal sealed class TestProgressState(long id, string assembly, string? target public IStopwatch Stopwatch { get; } = stopwatch; - public List Attachments { get; } = []; - - public List Messages { get; } = []; + public int FailedTests { get; private set; } - public int FailedTests { get; internal set; } + public int PassedTests { get; private set; } - public int PassedTests { get; internal set; } + public int SkippedTests { get; private set; } - public int SkippedTests { get; internal set; } + public int TotalTests => PassedTests + SkippedTests + FailedTests; - public int TotalTests { get; internal set; } - - public int RetriedFailedTests { get; internal set; } + public int RetriedFailedTests { get; private set; } public TestNodeResultsState? TestNodeResultsState { get; internal set; } @@ -38,20 +36,99 @@ internal sealed class TestProgressState(long id, string assembly, string? target public long Version { get; internal set; } public List<(string? DisplayName, string? UID)> DiscoveredTests { get; internal set; } = []; + public int? ExitCode { get; internal set; } + public bool Success { get; internal set; } - public List Tries { get; } = []; + public int TryCount { get; internal set; } + public HashSet FlakyTests { get; } = []; - internal void AddError(string text) - => Messages.Add(new ErrorMessage(text)); + public void ReportPassingTest(string testNodeUid, string instanceId) + { + if (_testUidToResults.TryGetValue(testNodeUid, out var value)) + { + if (value.LastInstanceId == instanceId) + { + // We are getting a test result for the same instance id. + value.Passed++; + _testUidToResults[testNodeUid] = value; + } + else + { + // We are getting a test result for a different instance id. + // This means that the test was retried. + // We discard the results from the previous instance id + RetriedFailedTests++; + PassedTests -= value.Passed; + SkippedTests -= value.Skipped; + FailedTests -= value.Failed; + _testUidToResults[testNodeUid] = (Passed: 1, Skipped: 0, Failed: 0, LastInstanceId: instanceId); + } + } + else + { + // This is the first time we see this test node. + _testUidToResults.Add(testNodeUid, (Passed: 1, Skipped: 0, Failed: 0, LastInstanceId: instanceId)); + } + + PassedTests++; + } + + public void ReportSkippedTest(string testNodeUid, string instanceId) + { + if (_testUidToResults.TryGetValue(testNodeUid, out var value)) + { + if (value.LastInstanceId == instanceId) + { + value.Skipped++; + _testUidToResults[testNodeUid] = value; + } + else + { + PassedTests -= value.Passed; + SkippedTests -= value.Skipped; + FailedTests -= value.Failed; + _testUidToResults[testNodeUid] = (Passed: 0, Skipped: 1, Failed: 0, LastInstanceId: instanceId); + } + } + else + { + _testUidToResults.Add(testNodeUid, (Passed: 0, Skipped: 1, Failed: 0, LastInstanceId: instanceId)); + } + + SkippedTests++; + } - internal void AddWarning(string text) - => Messages.Add(new WarningMessage(text)); + public void ReportFailedTest(string testNodeUid, string instanceId) + { + if (_testUidToResults.TryGetValue(testNodeUid, out var value)) + { + if (value.LastInstanceId == instanceId) + { + value.Failed++; + _testUidToResults[testNodeUid] = value; + } + else + { + PassedTests -= value.Passed; + SkippedTests -= value.Skipped; + FailedTests -= value.Failed; + _testUidToResults[testNodeUid] = (Passed: 0, Skipped: 0, Failed: 1, LastInstanceId: instanceId); + } + } + else + { + _testUidToResults.Add(testNodeUid, (Passed: 0, Skipped: 0, Failed: 1, LastInstanceId: instanceId)); + } + + FailedTests++; + } - internal void ClearAllMessages() + public void DiscoverTest(string displayName, string uid) { - Messages.Clear(); + PassedTests++; + DiscoveredTests.Add(new(displayName, uid)); } } diff --git a/src/sdk/src/Cli/dotnet/Commands/Test/TestApplicationEventHandlers.cs b/src/sdk/src/Cli/dotnet/Commands/Test/TestApplicationEventHandlers.cs index 51b59105ce2..7a29f576841 100644 --- a/src/sdk/src/Cli/dotnet/Commands/Test/TestApplicationEventHandlers.cs +++ b/src/sdk/src/Cli/dotnet/Commands/Test/TestApplicationEventHandlers.cs @@ -8,19 +8,26 @@ namespace Microsoft.DotNet.Cli.Commands.Test; internal sealed class TestApplicationsEventHandlers(TerminalTestReporter output) : IDisposable { - private readonly ConcurrentDictionary _executions = new(); + private readonly ConcurrentDictionary _executions = new(); private readonly TerminalTestReporter _output = output; public void OnHandshakeReceived(object sender, HandshakeArgs args) { - var testApplication = (TestApplication)sender; - var executionId = args.Handshake.Properties[HandshakeMessagePropertyNames.ExecutionId]; - var instanceId = args.Handshake.Properties[HandshakeMessagePropertyNames.InstanceId]; - var arch = args.Handshake.Properties[HandshakeMessagePropertyNames.Architecture]?.ToLower(); - var tfm = TargetFrameworkParser.GetShortTargetFramework(args.Handshake.Properties[HandshakeMessagePropertyNames.Framework]); - (string ModulePath, string TargetFramework, string Architecture, string ExecutionId, string InstanceId) appInfo = new(testApplication.Module.RunProperties.RunCommand, tfm, arch, executionId, instanceId); - _executions[testApplication] = appInfo; - _output.AssemblyRunStarted(appInfo.ModulePath, appInfo.TargetFramework, appInfo.Architecture, appInfo.ExecutionId, appInfo.InstanceId); + var hostType = args.Handshake.Properties[HandshakeMessagePropertyNames.HostType]; + // https://github.com/microsoft/testfx/blob/2a9a353ec2bb4ce403f72e8ba1f29e01e7cf1fd4/src/Platform/Microsoft.Testing.Platform/Hosts/CommonTestHost.cs#L87-L97 + if (hostType == "TestHost") + { + // AssemblyRunStarted counts "retry count", and writes to terminal "(Try ) Running tests from " + // So, we want to call it only for test host, and not for test host controller (or orchestrator, if in future it will handshake as well) + // Calling it for both test host and test host controllers means we will count retries incorrectly, and will messages twice. + var testApplication = (TestApplication)sender; + var executionId = args.Handshake.Properties[HandshakeMessagePropertyNames.ExecutionId]; + var arch = args.Handshake.Properties[HandshakeMessagePropertyNames.Architecture]?.ToLower(); + var tfm = TargetFrameworkParser.GetShortTargetFramework(args.Handshake.Properties[HandshakeMessagePropertyNames.Framework]); + (string ModulePath, string TargetFramework, string Architecture, string ExecutionId) appInfo = new(testApplication.Module.RunProperties.RunCommand, tfm, arch, executionId); + _executions[testApplication] = appInfo; + _output.AssemblyRunStarted(appInfo.ModulePath, appInfo.TargetFramework, appInfo.Architecture, appInfo.ExecutionId); + } LogHandshake(args); } @@ -57,6 +64,11 @@ public void OnDiscoveredTestsReceived(object sender, DiscoveredTestEventArgs arg public void OnTestResultsReceived(object sender, TestResultEventArgs args) { + // TODO: If we got some results for ExecutionId1 and InstanceId1 + // Then we started getting ExecutionId1 and InstanceId2, + // Then we started getting ExecutionId1 and InstanceId1 again. + // Should we discard the last result from ExecutionId1 and InstanceId1 completely? + // Or is it considered a violation of the protocol and should never happen? (in that case maybe we should throw?) var testApp = (TestApplication)sender; var appInfo = _executions[testApp]; diff --git a/src/sdk/src/Cli/dotnet/SlnFileFactory.cs b/src/sdk/src/Cli/dotnet/SlnFileFactory.cs index 7ad160cfba2..df75d138a99 100644 --- a/src/sdk/src/Cli/dotnet/SlnFileFactory.cs +++ b/src/sdk/src/Cli/dotnet/SlnFileFactory.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Text.Json; using Microsoft.DotNet.Cli.Utils; using Microsoft.VisualStudio.SolutionPersistence; @@ -11,6 +12,9 @@ namespace Microsoft.DotNet.Cli; public static class SlnFileFactory { + public static readonly string[] DefaultPlatforms = new[] { "Any CPU", "x64", "x86" }; + public static readonly string[] DefaultBuildTypes = new[] { "Debug", "Release" }; + public static string GetSolutionFileFullPath(string slnFileOrDirectory, bool includeSolutionFilterFiles = false, bool includeSolutionXmlFiles = true) { // Throw error if slnFileOrDirectory is an invalid path @@ -63,11 +67,17 @@ public static SolutionModel CreateFromFileOrDirectory(string fileOrDirectory, bo { return CreateFromFilteredSolutionFile(solutionPath); } - ISolutionSerializer serializer = SolutionSerializers.GetSerializerByMoniker(solutionPath) ?? throw new GracefulException( - CliStrings.CouldNotFindSolutionOrDirectory, - solutionPath); - - return serializer.OpenAsync(solutionPath, CancellationToken.None).Result; + try + { + ISolutionSerializer serializer = SolutionSerializers.GetSerializerByMoniker(solutionPath)!; + return serializer.OpenAsync(solutionPath, CancellationToken.None).Result; + } + catch (Exception ex) + { + throw new GracefulException( + CliStrings.InvalidSolutionFormatString, + solutionPath, ex.Message); + } } public static SolutionModel CreateFromFilteredSolutionFile(string filteredSolutionPath) diff --git a/src/sdk/src/Layout/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers.proj b/src/sdk/src/Layout/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers.proj index 4431ce8bd9d..bb4234adee1 100644 --- a/src/sdk/src/Layout/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers.proj +++ b/src/sdk/src/Layout/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers.proj @@ -24,12 +24,19 @@ - - - - - - + + + + + + + + + + + + + linux-$(TargetArchitecture) true + + <_GlobalPropertiesToRemoveFromProjectReferences>$(_GlobalPropertiesToRemoveFromProjectReferences);OutputPath - - - @@ -42,7 +42,7 @@ $(RepoRoot)documentation/manpages/sdk - + @@ -52,6 +52,7 @@ + + + - - - - - + + diff --git a/src/sdk/src/Layout/redist/targets/GenerateArchives.targets b/src/sdk/src/Layout/redist/targets/GenerateArchives.targets index 8f4c0068ac2..b9f9526fae5 100644 --- a/src/sdk/src/Layout/redist/targets/GenerateArchives.targets +++ b/src/sdk/src/Layout/redist/targets/GenerateArchives.targets @@ -2,7 +2,7 @@ + AfterTargets="AfterBuild"> diff --git a/src/sdk/src/Layout/redist/targets/GenerateInstallerLayout.targets b/src/sdk/src/Layout/redist/targets/GenerateInstallerLayout.targets index 03553154fc3..df5a33ccd90 100644 --- a/src/sdk/src/Layout/redist/targets/GenerateInstallerLayout.targets +++ b/src/sdk/src/Layout/redist/targets/GenerateInstallerLayout.targets @@ -83,7 +83,7 @@ LayoutWorkloadUserLocalMarker; CrossgenLayout; ReplaceBundledRuntimePackFilesWithSymbolicLinks" - AfterTargets="Build" /> + AfterTargets="AfterBuild" /> diff --git a/src/sdk/src/Layout/redist/targets/GenerateLayout.targets b/src/sdk/src/Layout/redist/targets/GenerateLayout.targets index 7938cfcd286..8dbccd2b381 100644 --- a/src/sdk/src/Layout/redist/targets/GenerateLayout.targets +++ b/src/sdk/src/Layout/redist/targets/GenerateLayout.targets @@ -546,6 +546,6 @@ RetargetTools; RemoveResourcesFromDotnetDeps; ChmodPublishDir" - AfterTargets="Build" /> + AfterTargets="AfterBuild" /> diff --git a/src/sdk/src/Layout/redist/targets/GenerateMSIs.targets b/src/sdk/src/Layout/redist/targets/GenerateMSIs.targets index b0092ff3d7a..653bed2cfb0 100644 --- a/src/sdk/src/Layout/redist/targets/GenerateMSIs.targets +++ b/src/sdk/src/Layout/redist/targets/GenerateMSIs.targets @@ -378,7 +378,7 @@ diff --git a/src/sdk/src/Layout/redist/targets/GeneratePKG.targets b/src/sdk/src/Layout/redist/targets/GeneratePKG.targets index bcda1fceee6..3ace3e40a7f 100644 --- a/src/sdk/src/Layout/redist/targets/GeneratePKG.targets +++ b/src/sdk/src/Layout/redist/targets/GeneratePKG.targets @@ -226,7 +226,7 @@ diff --git a/src/sdk/src/Layout/redist/targets/OverlaySdkOnLKG.targets b/src/sdk/src/Layout/redist/targets/OverlaySdkOnLKG.targets index e5ffe77350f..76c6c40bcbd 100644 --- a/src/sdk/src/Layout/redist/targets/OverlaySdkOnLKG.targets +++ b/src/sdk/src/Layout/redist/targets/OverlaySdkOnLKG.targets @@ -4,7 +4,7 @@ $(ArtifactsBinDir)redist\$(Configuration)\dotnet\ - + <_DotNetHiveRoot>$(DOTNET_INSTALL_DIR) <_DotNetHiveRoot Condition="'$(_DotNetHiveRoot)' == ''">$(RepoRoot).dotnet/ diff --git a/src/sdk/test/TestAssets/TestProjects/TestAppSimpleWithRetry/TestAppSimpleWithRetry.csproj b/src/sdk/test/TestAssets/TestProjects/TestAppSimpleWithRetry/TestAppSimpleWithRetry.csproj new file mode 100644 index 00000000000..c1f968cc69d --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/TestAppSimpleWithRetry/TestAppSimpleWithRetry.csproj @@ -0,0 +1,17 @@ + + + + + $(CurrentTargetFramework) + Exe + + $(TestingPlatformCommandLineArguments) --retry-failed-tests 3 --crashdump + true + + + + + + + + diff --git a/src/sdk/test/TestAssets/TestProjects/TestAppSimpleWithRetry/TestClass1.cs b/src/sdk/test/TestAssets/TestProjects/TestAppSimpleWithRetry/TestClass1.cs new file mode 100644 index 00000000000..8bd3b5c77d7 --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/TestAppSimpleWithRetry/TestClass1.cs @@ -0,0 +1,19 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[TestClass] +public class TestClass1 +{ + [TestMethod] + public void TestMethod1() + { + if (Environment.GetCommandLineArgs().Any(arg => arg.Contains("Retries") && !arg.EndsWith("2"))) + { + Assert.Fail("Failing..."); + } + } +} \ No newline at end of file diff --git a/src/sdk/test/TestAssets/TestProjects/TestAppSimpleWithRetry/dotnet.config b/src/sdk/test/TestAssets/TestProjects/TestAppSimpleWithRetry/dotnet.config new file mode 100644 index 00000000000..28daa0a2821 --- /dev/null +++ b/src/sdk/test/TestAssets/TestProjects/TestAppSimpleWithRetry/dotnet.config @@ -0,0 +1,2 @@ +[dotnet.test.runner] +name= "Microsoft.Testing.Platform" \ No newline at end of file diff --git a/src/sdk/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTests.cs b/src/sdk/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTests.cs index 2b61a07b29e..b5a51200a91 100644 --- a/src/sdk/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTests.cs +++ b/src/sdk/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsTests.cs @@ -39,6 +39,33 @@ public void RunTestProjectWithNoTests_ShouldReturnExitCodeGenericFailure(string result.ExitCode.Should().Be(ExitCodes.ZeroTests); } + [InlineData(TestingConstants.Debug)] + [InlineData(TestingConstants.Release)] + [Theory] + public void RunTestProjectWithWithRetryFeature_ShouldSucceed(string configuration) + { + TestAsset testInstance = _testAssetsManager.CopyTestAsset("TestAppSimpleWithRetry", Guid.NewGuid().ToString()) + .WithSource(); + + CommandResult result = new DotnetTestCommand(Log, disableNewOutput: false) + .WithWorkingDirectory(testInstance.Path) + .Execute(TestingPlatformOptions.ConfigurationOption.Name, configuration); + + if (!TestContext.IsLocalized()) + { + result.StdOut + .Should().Contain("(try 2)") + .And.NotContain("(try 3)") + .And.NotContain("(try 4)") + .And.Contain("total: 1 (+1 retried)") + .And.Contain("succeeded: 1") + .And.Contain("failed: 0") + .And.Contain("skipped: 0"); + } + + result.ExitCode.Should().Be(ExitCodes.Success); + } + [InlineData(TestingConstants.Debug)] [InlineData(TestingConstants.Release)] [Theory] diff --git a/src/source-build-externals/.gitmodules b/src/source-build-externals/.gitmodules index 731c2cdf669..a0f64eca781 100644 --- a/src/source-build-externals/.gitmodules +++ b/src/source-build-externals/.gitmodules @@ -1,22 +1,22 @@ -[submodule "src/application-insights"] +[submodule "application-insights"] path = src/application-insights url = https://github.com/microsoft/ApplicationInsights-dotnet -[submodule "src/cssparser"] +[submodule "cssparser"] path = src/cssparser url = https://github.com/dotnet/cssparser -[submodule "src/humanizer"] +[submodule "humanizer"] path = src/humanizer url = https://github.com/Humanizr/Humanizer -[submodule "src/newtonsoft-json"] +[submodule "newtonsoft-json"] path = src/newtonsoft-json url = https://github.com/JamesNK/Newtonsoft.Json.git -[submodule "src/MSBuildLocator"] +[submodule "MSBuildLocator"] path = src/MSBuildLocator url = https://github.com/microsoft/MSBuildLocator -[submodule "src/azure-activedirectory-identitymodel-extensions-for-dotnet"] +[submodule "azure-activedirectory-identitymodel-extensions-for-dotnet"] path = src/azure-activedirectory-identitymodel-extensions-for-dotnet url = https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet.git -[submodule "src/docker-creds-provider"] +[submodule "docker-creds-provider"] path = src/docker-creds-provider url = https://github.com/mthalman/docker-creds-provider [submodule "xunit"] @@ -25,6 +25,6 @@ [submodule "abstractions-xunit"] path = src/abstractions-xunit url = https://github.com/xunit/abstractions.xunit -[submodule "src/vs-solutionpersistence"] +[submodule "vs-solutionpersistence"] path = src/vs-solutionpersistence url = https://github.com/microsoft/vs-solutionpersistence.git diff --git a/src/source-build-externals/.vsts.pipelines/builds/ci-public.yml b/src/source-build-externals/.vsts.pipelines/builds/ci-public.yml index 509f394bf85..45ded124066 100644 --- a/src/source-build-externals/.vsts.pipelines/builds/ci-public.yml +++ b/src/source-build-externals/.vsts.pipelines/builds/ci-public.yml @@ -28,12 +28,6 @@ stages: jobs: - template: /eng/common/templates/jobs/jobs.yml parameters: - enablePublishUsingPipelines: true - enablePublishBuildAssets: true - artifacts: - publish: - artifacts: true - manifests: true jobs: - job: SourceBuild_Managed displayName: Source-Build (Managed) diff --git a/src/source-build-externals/.vsts.pipelines/builds/ci.yml b/src/source-build-externals/.vsts.pipelines/builds/ci.yml index 82b4a287af6..e76b02a5a71 100644 --- a/src/source-build-externals/.vsts.pipelines/builds/ci.yml +++ b/src/source-build-externals/.vsts.pipelines/builds/ci.yml @@ -49,12 +49,6 @@ extends: jobs: - template: /eng/common/templates-official/jobs/jobs.yml@self parameters: - enablePublishUsingPipelines: true - enablePublishBuildAssets: true - artifacts: - publish: - artifacts: true - manifests: true jobs: - job: SourceBuild_Managed displayName: Source-Build (Managed) @@ -72,9 +66,5 @@ extends: - checkout: self submodules: recursive - template: /eng/common/templates-official/steps/source-build.yml - - ${{ if notin(variables['Build.Reason'], 'PullRequest') }}: - - template: /eng/common/templates-official/post-build/post-build.yml@self - parameters: - publishingInfraVersion: 3 - enableSourceLinkValidation: true - enableSigningValidation: false + publishAssetsImmediately: true + isAssetlessBuild: true diff --git a/src/source-build-externals/Directory.Build.props b/src/source-build-externals/Directory.Build.props index c35fcb65ad9..1d6f551e571 100644 --- a/src/source-build-externals/Directory.Build.props +++ b/src/source-build-externals/Directory.Build.props @@ -1,85 +1,23 @@ - false - <_SuppressSdkImports>true - Release + Release - - - - netstandard2.0 - - false - + - + false - - $(MSBuildThisFileDirectory) - $(ProjectDir)targets/ $(ProjectDir)keys/ - $([MSBuild]::EnsureTrailingSlash('$(CustomDotNetSdkDir)')) - $([MSBuild]::NormalizeDirectory('$(DOTNET_INSTALL_DIR)')) - $(ProjectDir).dotnet/ - $(DotNetCliToolDir)dotnet + $(ProjectDir)src/ $(ProjectDir)patches/ - - $(NETCoreSdkVersion) - $(MSBuildThisFileDirectory)eng/tasks/Microsoft.DotNet.SourceBuild.Tasks.XPlat/ - $(XPlatTasksDir)bin/$(Configuration)/ - $(XPlatTasksBinDir)Microsoft.DotNet.SourceBuild.Tasks.XPlat.dll - $(DotNetCliToolDir)sdk/$(SDK_VERSION)/ - - - - - false - - - - minimal - - - - false - + $([MSBuild]::NormalizePath('$(ArtifactsBinDir)', 'Microsoft.DotNet.SourceBuild.Tasks.XPlat', '$(Configuration)', '$(NetCurrent)', 'Microsoft.DotNet.SourceBuild.Tasks.XPlat.dll')) - - .cmd - .sh - .zip - .tar.gz - - - - $(ProjectDir)src/ - $(ProjectDir).gitmodules - - - - - $(ProjectDir)artifacts/ - $(ProjectDir)eng/ - - - - $(ArtifactsShippingPackagesDir) - $(BaseOutputPath)logs/ - - - - - $(BaseIntermediatePath)semaphores/ + minimal + false diff --git a/src/source-build-externals/Directory.Build.targets b/src/source-build-externals/Directory.Build.targets index 3eb8cfad189..f90f13fc365 100644 --- a/src/source-build-externals/Directory.Build.targets +++ b/src/source-build-externals/Directory.Build.targets @@ -1,5 +1,5 @@ - + diff --git a/src/source-build-externals/build.sh b/src/source-build-externals/build.sh index d6588ae3048..b3236325088 100755 --- a/src/source-build-externals/build.sh +++ b/src/source-build-externals/build.sh @@ -13,11 +13,4 @@ while [[ -h $source ]]; do done scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" - -sdkLine=$(grep -m 1 'dotnet' "$scriptroot/global.json") -sdkPattern="\"dotnet\" *: *\"(.*)\"" -if [[ $sdkLine =~ $sdkPattern ]]; then - export SDK_VERSION=${BASH_REMATCH[1]} -fi - "$scriptroot/eng/common/build.sh" --build --restore "$@" diff --git a/src/source-build-externals/check-submodules.ps1 b/src/source-build-externals/check-submodules.ps1 deleted file mode 100644 index a08f827d5cc..00000000000 --- a/src/source-build-externals/check-submodules.ps1 +++ /dev/null @@ -1,179 +0,0 @@ -$answeredAll = $false # has the user answered "yes to all" to init'ing submodules? -$ProjectRoot = $PSScriptRoot -$CleanAllSentinel = "$ProjectRoot\.cleansourcebuildsubmodules" -# How long to wait between polling for input on ReadKey. -# This affects apparent responsiveness so setting it fairly low. -$InputPollingTime = 100 # ms -$InputCountTimeout = (30 * 1000) / $InputPollingTime # ms - -function WaitForInput() { - $counter = 0 - while (-Not [Console]::KeyAvailable -and ($counter++ -lt $InputCountTimeout)) { - Start-Sleep -Milliseconds $InputPollingTime - } - if ([Console]::KeyAvailable) { - $k = [Console]::ReadKey() - return $k - } - return $null -} - -# ask for confirmation and initialize a submodule if approved. -function init_submodule($Path) { - $done = $false - while (-Not $done) { - Write-Warning "submodule $Path does not appear to be initialized." - Write-Host "Should I initialize it for you [Y]es / [n]o / [a]ll / [q]uit" - $answer = WaitForInput - if ($answer -eq $null -or $answer.KeyChar -ieq "a") { - $script:answeredAll = $true - $done = $true - git submodule update --init --recursive $Path - } - elseif ($answer.KeyChar -ieq "q") { - exit 1 - } - elseif ($answer.KeyChar -ieq "y" -or $answer.Key -eq [System.ConsoleKey]::Spacebar -or $answer.Key -eq [System.ConsoleKey]::Enter) { - $done = $true - git submodule update --init --recursive $Path - } - elseif ($answer.KeyChar -ieq "n") { - $done = $true - } - else { - Write-Host "Didn't understand that ($($answer.KeyChar))" - } - } -} - -# update a submodule to an expected commit. We give different messages -# for being ahead vs being behind or diverged from the expected commit, -# so this function is parameterized. -function fix_submodule($Path, $ExpectedSha, $ActualSha, $Message, $Prompt) { - $done = $false - while (-Not $done) { - Write-Warning $Message - Write-Host $Prompt - $answer = WaitForInput - if ($answer -eq $null -or $answer.KeyChar -ieq "n" -or $answer.Key -eq [System.ConsoleKey]::Spacebar -or $answer.Key -eq [System.ConsoleKey]::Enter) { - $done = $true - } - elseif ($answer.KeyChar -ieq "q") { - exit 1 - } - elseif ($answer.KeyChar -ieq "y") { - # check if we have this commit locally and can skip the fetch - git cat-file -e $expectedSha^`{commit`} 2>&1 | Out-Null - if ($LastExitCode -ne 0) { - git fetch - } - # double-check, we should have the commit now unless something - # weird is going on. - git cat-file -e $expectedSha^`{commit`} 2>&1 | Out-Null - if ($LastExitCode -ne 0) { - Write-Error "commit $expectedSha was not found in $path" - Write-Host "The remote may have changed in source-build; run 'git submodule sync' and retry." - Write-Host "Are you using a custom remote for this submodule? You may need to pick up changes from upstream." - Write-Host "Canceling remainder of checks." - exit 1 - } - git checkout $expectedSha - $done = $true - } - else { - Write-Host "Didn't understand that ($($answer.KeyChar))" - } - } -} - -# clean a submodule if the user approves. -function clean_submodule($Path, $Message, $Prompt) { - $done = $false - while (-Not $done) { - Write-Warning $Message - Write-Host $Prompt - $answer = WaitForInput - if ($answer -eq $null -or $answer.KeyChar -ieq "n" -or $answer.Key -eq [System.ConsoleKey]::Spacebar -or $answer.Key -eq [System.ConsoleKey]::Enter) { - $done = $true - } - elseif ($answer.KeyChar -ieq "a") { - git clean -fxd - git reset --hard HEAD - New-Item -ItemType File $CleanAllSentinel | Out-Null - $done = $true - } - elseif ($answer.KeyChar -ieq "q") { - exit 1 - } - elseif ($answer.KeyChar -ieq "y") { - git clean -fxd - git reset --hard HEAD - $done = $true - } - else { - Write-Host "Didn't understand that ($($answer.KeyChar))" - } - } -} - -# We use the same script for checking the super-repo and the submodules. -# Having the first argument be "in-submodule" triggers this submodule behavior. -if ($args[0] -ieq "in-submodule") { - $path = $args[1] - $expectedSha = $args[2] - $subcommit = git rev-parse HEAD - if ($subcommit -ne $expectedSha) { - # merge-base fails if the commit is missing, so check for that first. - git cat-file -e $expectedSha^`{commit`} 2>&1 | Out-Null - if ($LastExitCode -ne 0) { - $mergeBase = "missing commit" - } - else { - $mergeBase = git merge-base HEAD $expectedSha - } - if ($mergeBase -ne $expectedSha) { - fix_submodule -Path $path -ExpectedSha $expectedSha -ActualSha $subcommit -Message "submodule $path, currently at $subcommit, has diverged from checked-in version $expectedSha" -Prompt "If you are changing a submodule branch or moving a submodule backwards, this is expected.`r`nShould I checkout $path to the expected commit $expectedSha [N]o / [y]es / [q]uit" - } - else { - fix_submodule -Path $path -ExpectedSha $expectedSha -ActualSha $subcommit -Message "submodule $path, currently at $subcommit, is ahead of checked-in version $expectedSha" -Prompt "If you are updating a submodule, this is expected.`r`nShould I checkout $path to the expected commit $expectedSha [N]o / [y]es / [q]uit" - } - } - $dirty = $false - # check for staged changes and unstaged modifications - git diff-index --quiet HEAD -- - $dirty = $dirty -or $LastExitCode - # check for untracked new files - $untracked = git ls-files --others --exclude-standard - $dirty = $dirty -or (-Not [string]::IsNullOrWhitespace($untracked)) - if ($dirty) { - if (Test-Path $CleanAllSentinel) { - git clean -fxd - git reset --hard HEAD - } - else { - clean_submodule -Path $path -Message "submodule $path has uncommitted changes" -Prompt "Should I clean and reset $path (this will lose ALL uncommitted changes)? [N]o / [y]es / [a]ll / [q]uit" - } - } -} -# Main branch for super-repo behavior -else { - # submodule foreach doesn't work until submodules are init'd, read the modules manually - $modules = git config --file $ProjectRoot\.gitmodules --get-regexp path - foreach ($m in $modules) { - $m = $m.Split(' ')[1] - $mWin = $m.Replace('/', '\') - if (-Not (Test-Path "$ProjectRoot\$mWin\.git")) { - if ($script:answeredAll) { - git submodule update --init --recursive $m - } - else { - init_submodule -Path $m - } - } - } - $ProjectRoot = $ProjectRoot.Replace('\', '/') - # kick off the submodule behavior for each repo - Remove-Item -Force -ErrorAction SilentlyContinue $CleanAllSentinel - git submodule foreach --quiet --recursive "powershell $ProjectRoot/check-submodules.ps1 in-submodule `$path `$sha1" - Remove-Item -Force -ErrorAction SilentlyContinue $CleanAllSentinel -} diff --git a/src/source-build-externals/check-submodules.sh b/src/source-build-externals/check-submodules.sh deleted file mode 100755 index 08832e3afe1..00000000000 --- a/src/source-build-externals/check-submodules.sh +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail -IFS=$'\n\t' - -SCRIPT_ROOT="$(cd -P "$( dirname "$0" )" && pwd)" -SUBMODULES="$SCRIPT_ROOT/.gitmodules" -CLEAN_ALL_SENTINEL="$SCRIPT_ROOT/.cleansourcebuildsubmodules" -PROMPT_TIMEOUT=30 - -# has the user answered "yes to all" to init'ing submodules? -answered_all=0 - -# ask for confirmation and initialize a submodule if approved. -init_submodule () { - module=$1 - done=0 - while [ $done == 0 ]; do - noreply=0 - echo "warning: submodules $module does not appear to be initialized." - read -p "Should I initialize it for you? [Y]es / [n]o / [a]ll / [q]uit] " -n 1 -r -t $PROMPT_TIMEOUT || noreply=1 - echo - if [[ $noreply == 1 || $REPLY =~ ^[Aa]$ ]]; then - answered_all=1 - done=1 - git submodule update --init --recursive "$module" - elif [[ $REPLY =~ ^[Qq]$ ]]; then - exit 0 - elif [[ $REPLY =~ ^[Nn]$ ]]; then - done=1 - elif [[ $REPLY == "" || $REPLY == " " || $REPLY =~ ^[Yy]$ ]]; then - done=1 - git submodule update --init --recursive "$module" - else - echo "didn't understand that ($REPLY)" - fi - done -} - -# update a submodule to an expected commit. We give different messages -# for being ahead vs being behind or diverged from the expected commit, -# so this function is parameterized. -fix_submodule () { - path="$1" - expected=$2 - actual=$3 - msg="$4" - prompt="$5" - done=0 - while [ $done == 0 ]; do - noreply=0 - echo -e "$msg" - read -p "$prompt " -n 1 -r -t $PROMPT_TIMEOUT || noreply=1 - echo - if [[ $noreply == 1 || $REPLY == "" || $REPLY == " " || $REPLY =~ ^[Nn]$ ]]; then - done=1 - elif [[ $REPLY =~ ^[Qq]$ ]]; then - exit 1 - elif [[ $REPLY =~ ^[Yy]$ ]]; then - # check if we have this commit locally and can skip the fetch - git cat-file -e $expected^{commit} 2>/dev/null || exitCode=$? - if [ $exitCode != 0 ]; then - git fetch - fi - exitCode=0 - # double-check, we should have the commit now unless something - # weird is going on. - git cat-file -e $expected^{commit} 2>/dev/null || exitCode=$? - if [ $exitCode != 0 ]; then - echo "error: commit $expected was not found in $path" - echo "The remote may have changed in source-build; run 'git submodule sync' and retry." - echo "Are you using a custom remote for this submodule? You may need to pick up changes from upstream." - echo "Canceling remainder of checks." - exit 1 - fi - git checkout $expected - done=1 - else - echo "didn't understand that ($REPLY)" - fi - done -} - -# clean a submodule if the user approves. -clean_submodule() { - path="$1" - msg="$2" - prompt="$3" - done=0 - while [ $done == 0 ]; do - noreply=0 - echo -e "$msg" - read -p "$prompt " -n 1 -r -t $PROMPT_TIMEOUT || noreply=1 - echo - if [[ $noreply == 1 || $REPLY == "" || $REPLY == " " || $REPLY =~ ^[Nn]$ ]]; then - done=1 - elif [[ $REPLY =~ ^[Aa]$ ]]; then - git clean -fxd - git reset --hard HEAD - touch "$CLEAN_ALL_SENTINEL" - done=1 - elif [[ $REPLY =~ ^[Qq]$ ]]; then - exit 1 - elif [[ $REPLY =~ ^[Yy]$ ]]; then - git clean -fxd - git reset --hard HEAD - done=1 - else - echo "didn't understand that ($REPLY)" - fi - done -} - -# We use the same script for checking the super-repo and the submodules. -# Having the first argument be "in-submodule" triggers this submodule behavior. -if [ ${1:-default} == "in-submodule" ]; then - path="$2" - expected_sha=$3 - subcommit=`git rev-parse HEAD` - if [ "$subcommit" != "$expected_sha" ]; then - exitCode=0 - # merge-base fails if the commit is missing, so check for that first. - git cat-file -e $expected_sha^{commit} 2>/dev/null || exitCode=$? - if [ $exitCode != 0 ]; then - mergeBase="missing commit" - else - mergeBase=$(git merge-base HEAD $expected_sha) - fi - if [ "$mergeBase" != "$expected_sha" ]; then - fix_submodule $path $expected_sha $subcommit "warning: submodule $path, currently at $subcommit, has diverged from checked-in version $expected_sha\nif you are changing a submodule branch or moving a submodule backwards, this is expected.\nShould I checkout $path to the expected commit $expected_sha?" "[N]o / [y]es / [q]uit" - else - fix_submodule $path $expected_sha $subcommit "warning: submodule $path, currently at $subcommit, is ahead of checked-in version $expected_sha\nif you are updating a submodule, this is expected.\nShould I checkout $path to the expected commit $expected_sha?" "[N]o / [y]es / [q]uit" - fi - fi - # check for staged changes and unstaged modifications - git diff-index --quiet HEAD -- || exit_code=$? - # check for untracked new files - untracked="$(git ls-files --others --exclude-standard)" - if [[ ${exit_code:-0} != 0 || ! -z "$untracked" ]]; then - if [ -e "$CLEAN_ALL_SENTINEL" ]; then - git clean -fxd - git reset --hard HEAD - else - clean_submodule $path "warning: submodule $path has uncommitted changes\nShould I clean and reset $path (this will lose ALL uncommitted changes)?" "[N]o / [y]es / [a]ll / [q]uit" - fi - fi -# Main branch for super-repo behavior -else - # submodule foreach doesn't work until submodules are init'd, read the modules manually - for module in `git config --file "$SUBMODULES" --get-regexp path | awk '{ print $2 }'` - do - if [ ! -e "$SCRIPT_ROOT/$module/.git" ]; then - if [ $answered_all == 1 ]; then - git submodule update --init --recursive "$module" - else - init_submodule "$module" - fi - fi - done - # kick off the submodule behavior for each repo - rm -f "$CLEAN_ALL_SENTINEL" - git submodule foreach --quiet --recursive "$SCRIPT_ROOT/check-submodules.sh in-submodule \"\$path\" \"\$sha1\"" - rm -f "$CLEAN_ALL_SENTINEL" -fi - diff --git a/src/source-build-externals/eng/Build.props b/src/source-build-externals/eng/Build.props index 4e8e180227f..5716ccfbba3 100644 --- a/src/source-build-externals/eng/Build.props +++ b/src/source-build-externals/eng/Build.props @@ -1,9 +1,6 @@ - - false - diff --git a/src/source-build-externals/eng/DotNetBuild.props b/src/source-build-externals/eng/DotNetBuild.props deleted file mode 100644 index 87513e41ecd..00000000000 --- a/src/source-build-externals/eng/DotNetBuild.props +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - source-build-externals - true - - - - - - - - diff --git a/src/source-build-externals/eng/Version.Details.xml b/src/source-build-externals/eng/Version.Details.xml index 33d06e6f7e6..ce9f6012263 100644 --- a/src/source-build-externals/eng/Version.Details.xml +++ b/src/source-build-externals/eng/Version.Details.xml @@ -1,14 +1,14 @@ - + https://github.com/dotnet/msbuild e9b99f554a3c298e1106ea171f5a0462780af2c5 - + https://github.com/dotnet/dotnet - efbfb137a317fb339a6b7be36af7188cc508dc95 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 diff --git a/src/source-build-externals/eng/Versions.props b/src/source-build-externals/eng/Versions.props index 9440c1c06fb..3343bb24f1a 100644 --- a/src/source-build-externals/eng/Versions.props +++ b/src/source-build-externals/eng/Versions.props @@ -1,5 +1,4 @@ - - + 10 diff --git a/src/source-build-externals/eng/common/core-templates/jobs/source-build.yml b/src/source-build-externals/eng/common/core-templates/jobs/source-build.yml index a10ccfbee6d..df24c948ba1 100644 --- a/src/source-build-externals/eng/common/core-templates/jobs/source-build.yml +++ b/src/source-build-externals/eng/common/core-templates/jobs/source-build.yml @@ -14,7 +14,7 @@ parameters: # This is the default platform provided by Arcade, intended for use by a managed-only repo. defaultManagedPlatform: name: 'Managed' - container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream9' + container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream-10-amd64' # Defines the platforms on which to run build jobs. One job is created for each platform, and the # object in this array is sent to the job template as 'platform'. If no platforms are specified, diff --git a/src/source-build-externals/eng/common/core-templates/steps/source-build.yml b/src/source-build-externals/eng/common/core-templates/steps/source-build.yml index 8c88ccd7b08..658d0d3ff9f 100644 --- a/src/source-build-externals/eng/common/core-templates/steps/source-build.yml +++ b/src/source-build-externals/eng/common/core-templates/steps/source-build.yml @@ -66,16 +66,6 @@ steps: baseOsArgs='/p:BaseOS=${{ parameters.platform.baseOS }}' fi - publishArgs= - if [ '${{ parameters.platform.skipPublishValidation }}' != 'true' ]; then - publishArgs='--publish' - fi - - assetManifestFileName=SourceBuild_RidSpecific.xml - if [ '${{ parameters.platform.name }}' != '' ]; then - assetManifestFileName=SourceBuild_${{ parameters.platform.name }}.xml - fi - portableBuildArgs= if [ '${{ parameters.platform.portableBuild }}' != '' ]; then portableBuildArgs='/p:PortableBuild=${{ parameters.platform.portableBuild }}' @@ -83,7 +73,7 @@ steps: ${{ coalesce(parameters.platform.buildScript, './build.sh') }} --ci \ --configuration $buildConfig \ - --restore --build --pack $publishArgs -bl \ + --restore --build --pack -bl \ ${{ parameters.platform.buildArguments }} \ $officialBuildArgs \ $internalRuntimeDownloadArgs \ @@ -94,7 +84,6 @@ steps: $portableBuildArgs \ /p:DotNetBuildSourceOnly=true \ /p:DotNetBuildRepo=true \ - /p:AssetManifestFileName=$assetManifestFileName displayName: Build # Upload build logs for diagnosis. @@ -121,14 +110,3 @@ steps: continueOnError: true condition: succeededOrFailed() sbomEnabled: false # we don't need SBOM for logs - -# Manually inject component detection so that we can ignore the source build upstream cache, which contains -# a nupkg cache of input packages (a local feed). -# This path must match the upstream cache path in property 'CurrentRepoSourceBuiltNupkgCacheDir' -# in src\Microsoft.DotNet.Arcade.Sdk\tools\SourceBuild\SourceBuildArcade.targets -- template: /eng/common/core-templates/steps/component-governance.yml - parameters: - displayName: Component Detection (Exclude upstream cache) - is1ESPipeline: ${{ parameters.is1ESPipeline }} - componentGovernanceIgnoreDirectories: '$(Build.SourcesDirectory)/artifacts/sb/src/artifacts/obj/source-built-upstream-cache' - disableComponentGovernance: ${{ eq(variables['System.TeamProject'], 'public') }} diff --git a/src/source-build-externals/eng/git-clone-to-dir.sh b/src/source-build-externals/eng/git-clone-to-dir.sh deleted file mode 100755 index 048c1745778..00000000000 --- a/src/source-build-externals/eng/git-clone-to-dir.sh +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/env bash - -usage() { - echo "$0 [options]" - echo "Creates a git clone of into directory, optionally saving WIP changes." - echo "" - echo "Required:" - echo " --source (Required) The source Git directory." - echo " --dest (Required) The destination Git directory. Created if doesn't exist." - echo "" - echo "Optional:" - echo " --clean If dest directory already exists, delete it." - echo " --copy-wip Transfer most types of uncommitted change into the" - echo " destination directory. Useful for dev workflows." - echo " -h --help Print help and exit." -} - -# An alternative to "git clone" would be to use a "git worktree". Potential benefits: -# * This has more integration with the user's normal repo. If they make ad-hoc changes in the -# worktree, it is easy to cherry-pick onto the developer's "real" branch. -# * A worktree uses a '.git' file rather than a full '.git' directory, which might have storage -# implications. (However, a local clone's '.git' directory uses hard links to save space/time, -# so it's not certain that this affects performance at all.) -# -# Downside of worktrees: -# * Some configuration is set up in '.git/worktrees' which may be difficult to coordinate -# properly. In particular, if the user is already using worktrees for their own purposes, we -# would have to be careful that running source-build in one worktree doesn't interfere with -# source-build in the other worktree. - -set -euo pipefail - -while [[ $# > 0 ]]; do - opt="$(echo "$1" | tr "[:upper:]" "[:lower:]")" - case "$opt" in - -h|--help) - usage - exit 0 - ;; - --source) - sourceDir="$2" - shift - ;; - --dest) - destDir="$2" - shift - ;; - --clean) - clean=1 - ;; - --copy-wip) - copyWip=1 - ;; - *) - echo "Unrecognized option: $1" - echo "" - usage - exit 1 - ;; - esac - shift -done - -[ ! -d "${sourceDir:-}" ] && echo "--source not a directory: $sourceDir" && exit 1 - -[ ! "${destDir:-}" ] && echo "--dest not specified" && exit 1 - -echo "Cloning repository at '$sourceDir' to '$destDir'..." - -if [ -e "$destDir" ]; then - echo "Destination already exists!" - if [ -f "$destDir" ]; then - echo "Existing destination is a regular file, not a directory. This is unusual: aborting." - exit 1 - elif [ "${clean:-}" ]; then - echo "Clean is enabled: removing $destDir and continuing..." - rm -rf "$destDir" - else - echo "Clean is not enabled: aborting." - exit 1 - fi -fi - -if [ ! -e "$destDir" ]; then - mkdir -p "$destDir" - - if [ "${copyWip:-}" ]; then - # Copy over changes that haven't been committed, for dev inner loop. - # This gets changes (whether staged or not) but misses untracked files. - stashCommit=$(cd "$sourceDir"; git stash create) - - if [ "$stashCommit" ]; then - echo "WIP changes detected: created temporary stash $stashCommit to transfer to inner repository..." - else - echo "No WIP changes detected..." - fi - fi - - echo "Creating empty clone at: $destDir" - - sourceGitDir=$(cd "$sourceDir" && git rev-parse --git-dir) - shallowFile="$sourceGitDir/shallow" - - if [ -f "$shallowFile" ]; then - echo "Source repository is shallow..." - if [ "${stashCommit:-}" ]; then - echo "WIP stash is not supported in a shallow repository: aborting." - exit 1 - fi - - # If source repo is shallow, old versions of Git refuse to clone it to another directory. First, - # remove the 'shallow' file to trick Git into allowing the clone. - shallowContent=$(cat "$shallowFile") - rm "$shallowFile" - - # Then, run the clone: - # * 'depth=1' avoids encountering the leaf commit in the shallow repo that points to a parent - # that doesn't exist. (The commit marked "grafted".) Git would fail here, otherwise. - # * '--no-local' allows a shallow clone from a git dir on the same filesystem. This means the - # clone will not use hard links and takes up more space. However, since we're doing a shallow - # clone anyway, the difference is probably not significant. (This has not been measured.) - git clone --depth=1 --no-local --no-checkout "$sourceDir" "$destDir" - - # Put the 'shallow' file back so operations on the outer Git repo continue to work normally. - printf "%s" "$shallowContent" > "$shallowFile" - else - git clone --no-checkout "$sourceDir" "$destDir" - fi - - ( - cd "$destDir" - echo "Checking out sources..." - # If no changes were stashed, stashCommit is empty string, and this is a simple checkout. - git checkout ${stashCommit:-} - ) - - echo "Clone complete: $sourceDir -> $destDir" -fi diff --git a/src/source-build-externals/eng/tasks/Directory.Build.props b/src/source-build-externals/eng/tasks/Directory.Build.props deleted file mode 100644 index 98448e986de..00000000000 --- a/src/source-build-externals/eng/tasks/Directory.Build.props +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - AnyCPU - - true - - - - - - - - - - diff --git a/src/source-build-externals/eng/tasks/Microsoft.DotNet.SourceBuild.Tasks.XPlat/Microsoft.DotNet.SourceBuild.Tasks.XPlat.csproj b/src/source-build-externals/eng/tasks/Microsoft.DotNet.SourceBuild.Tasks.XPlat/Microsoft.DotNet.SourceBuild.Tasks.XPlat.csproj index b73b383733e..8717017a732 100644 --- a/src/source-build-externals/eng/tasks/Microsoft.DotNet.SourceBuild.Tasks.XPlat/Microsoft.DotNet.SourceBuild.Tasks.XPlat.csproj +++ b/src/source-build-externals/eng/tasks/Microsoft.DotNet.SourceBuild.Tasks.XPlat/Microsoft.DotNet.SourceBuild.Tasks.XPlat.csproj @@ -2,10 +2,7 @@ $(NetCurrent) - $(XPlatTasksBinDir) - - False @@ -13,14 +10,8 @@ - - - - - - diff --git a/src/source-build-externals/eng/tasks/Microsoft.DotNet.SourceBuild.Tasks.XPlat/UpdateJson.cs b/src/source-build-externals/eng/tasks/Microsoft.DotNet.SourceBuild.Tasks.XPlat/UpdateJson.cs index 9820e4af233..96837121c14 100644 --- a/src/source-build-externals/eng/tasks/Microsoft.DotNet.SourceBuild.Tasks.XPlat/UpdateJson.cs +++ b/src/source-build-externals/eng/tasks/Microsoft.DotNet.SourceBuild.Tasks.XPlat/UpdateJson.cs @@ -1,20 +1,16 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. using System; using System.IO; using System.Linq; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; namespace Microsoft.DotNet.Build.Tasks { - // Takes a path to a path to a json file and a - // string that represents a dotted path to an attribute - // and updates that attribute with the new value provided. public class UpdateJson : Task { [Required] @@ -30,23 +26,26 @@ public class UpdateJson : Task public override bool Execute() { - JObject jsonObj = JObject.Parse(File.ReadAllText(JsonFilePath)); + string jsonText = File.ReadAllText(JsonFilePath); + JsonNode jsonNode = JsonNode.Parse(jsonText); string[] escapedPathToAttributeParts = PathToAttribute.Replace("\\.", "\x1F").Split('.'); for (int i = 0; i < escapedPathToAttributeParts.Length; ++i) { escapedPathToAttributeParts[i] = escapedPathToAttributeParts[i].Replace("\x1F", "."); } - UpdateAttribute(jsonObj, escapedPathToAttributeParts, NewAttributeValue); - File.WriteAllText(JsonFilePath, jsonObj.ToString()); + UpdateAttribute(jsonNode, escapedPathToAttributeParts, NewAttributeValue); + + File.WriteAllText(JsonFilePath, jsonNode.ToJsonString(new JsonSerializerOptions { WriteIndented = true })); return true; } - private void UpdateAttribute(JToken jsonObj, string[] path, string newValue) + private void UpdateAttribute(JsonNode node, string[] path, string newValue) { string pathItem = path[0]; - if (jsonObj[pathItem] == null) + + if (node is not JsonObject obj || !obj.ContainsKey(pathItem)) { string message = $"Path item [{nameof(PathToAttribute)}] not found in json file."; if (SkipUpdateIfMissingKey) @@ -57,13 +56,13 @@ private void UpdateAttribute(JToken jsonObj, string[] path, string newValue) throw new ArgumentException(message, pathItem); } - if (path.Length == 1) + if (path.Length == 1) { - jsonObj[pathItem] = newValue; + obj[pathItem] = newValue; return; } - UpdateAttribute(jsonObj[pathItem], path.Skip(1).ToArray(), newValue); + UpdateAttribute(obj[pathItem], path.Skip(1).ToArray(), newValue); } } } diff --git a/src/source-build-externals/global.json b/src/source-build-externals/global.json index 10335aa0cc4..cdad98fad97 100644 --- a/src/source-build-externals/global.json +++ b/src/source-build-externals/global.json @@ -3,6 +3,7 @@ "dotnet": "10.0.100-preview.3.25201.16" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25228.104" + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25251.105", + "Microsoft.Build.NoTargets": "3.7.0" } } diff --git a/src/source-build-externals/patches/abstractions-xunit/0001-Patching.patch b/src/source-build-externals/patches/abstractions-xunit/0001-Patching.patch index 3d0be07f748..d4d508096e8 100644 --- a/src/source-build-externals/patches/abstractions-xunit/0001-Patching.patch +++ b/src/source-build-externals/patches/abstractions-xunit/0001-Patching.patch @@ -4,24 +4,10 @@ Date: Wed, 19 Jul 2023 11:47:26 -0700 Subject: [PATCH] Patching --- - global.json | 6 ------ src/xunit.abstractions/Properties/AssemblyInfo.cs | 2 +- src/xunit.abstractions/xunit.abstractions.csproj | 11 +++-------- - 3 files changed, 4 insertions(+), 15 deletions(-) - delete mode 100644 global.json + 2 files changed, 4 insertions(+), 9 deletions(-) -diff --git a/global.json b/global.json -deleted file mode 100644 -index 9f78419..0000000 ---- a/global.json -+++ /dev/null -@@ -1,6 +0,0 @@ --{ -- "sdk": { -- "version": "6.0.0", -- "rollForward": "latestMinor" -- } --} diff --git a/src/xunit.abstractions/Properties/AssemblyInfo.cs b/src/xunit.abstractions/Properties/AssemblyInfo.cs index 041f22b..c5b5124 100644 --- a/src/xunit.abstractions/Properties/AssemblyInfo.cs @@ -56,6 +42,3 @@ index fa4cf23..5d61131 100644 - - --- -2.41.0.windows.2 - diff --git a/src/source-build-externals/repo-projects/Directory.Build.props b/src/source-build-externals/repo-projects/Directory.Build.props index e593913ee3f..576f5120763 100644 --- a/src/source-build-externals/repo-projects/Directory.Build.props +++ b/src/source-build-externals/repo-projects/Directory.Build.props @@ -1,50 +1,36 @@ - - $(MSBuildProjectName) - - - $(RepositoryName) - $(SubmoduleDirectory)$(SourceDirectory)/ - true - $(LoggingDir)$(RepositoryName).log - >> $(RepoConsoleLogFile) 2>&1 + $(NetCurrent) + $(MSBuildProjectName) - - $(CompletedSemaphorePath)$(RepositoryName)/ - + $([MSBuild]::NormalizeDirectory('$(SubmoduleDirectory)', '$(RepositoryName)')) + $([MSBuild]::NormalizeDirectory('$(OriginalProjectDirectory)', 'artifacts', 'clone')) + $([MSBuild]::NormalizeDirectory('$(ArtifactsLogDir)', '$(RepositoryName)')) - - - - 0 - - - -- - false + true + $(ArtifactsLogRepoDir)$(RepositoryName).log + > $(RepoConsoleLogFile) 2>&1 - - - '$(RepositoryName)' - + + + - - - + + + - - + + @@ -68,4 +54,9 @@ + + + + + diff --git a/src/source-build-externals/repo-projects/Directory.Build.targets b/src/source-build-externals/repo-projects/Directory.Build.targets index ee8bf0e95d6..5b374f4fc42 100644 --- a/src/source-build-externals/repo-projects/Directory.Build.targets +++ b/src/source-build-externals/repo-projects/Directory.Build.targets @@ -1,4 +1,6 @@ - + + + $(ProjectDirectory)NuGet.config @@ -7,11 +9,9 @@ $(ProjectDirectory)src\NuGet.Config - - - + <_DependentProject Include="@(RepositoryReference -> '%(Identity).proj')" /> @@ -19,15 +19,20 @@ - - - + + + + - + + + git --work-tree=$(ProjectDirectory) apply --ignore-whitespace --whitespace=nowarn @@ -37,12 +42,15 @@ when we are applying patches in the current directory (which is required due to the way Git interprets the paths in a patch). GIT_DIR=/dev/null short-circuits the .gitdir discovery process and lets Git treat the directory like any non-Git-controlled directory instead. --> - - + + + + - @@ -64,9 +71,10 @@ Add a new nuget config file at the root of the component that includes sources for its dependencies' outputs. --> + - + Condition="'@(RepositoryReference)' != ''" + DependsOnTargets="ResolveProjectReferences"> $(ProjectDirectory)NuGet.config @@ -103,20 +111,23 @@ + Outputs="$(BaseIntermediateOutputPath)UpdateNuGetConfig.complete"> - + + + + + + Outputs="$(BaseIntermediateOutputPath)UpdateGlobalJsonVersions.complete"> <_PossibleCliVersionJsonPath Include="sdk.version" /> <_PossibleCliVersionJsonPath Include="tools.dotnet" /> @@ -124,49 +135,51 @@ - + + + + - - + + - - + Outputs="$(BaseIntermediateOutputPath)RepoBuild.complete"> + + + + + - - - - - - - - - - - - $(BuildCommand) /v:$(LogVerbosity) $(RedirectRepoOutputToLog) - $(BuildCommand) $(RedirectRepoOutputToLog) - - + IgnoreStandardErrorWarningFormat="true" + Condition="'$(CustomRepoBuild)' != 'true'" /> + + + + + + + + + + + @@ -175,68 +188,27 @@ - - - - - - - - - + + - - - - - - - <_BuiltPackages Condition="'$(PackagesOutput)' != ''" Include="$(PackagesOutput)/*.nupkg" Exclude="$(PackagesOutput)/*.symbols.nupkg"/> - <_BuiltPackages Condition="'@(PackagesOutputList)' != ''" Include="%(PackagesOutputList.Identity)/*.nupkg" Exclude="%(PackagesOutputList.Identity)/*.symbols.nupkg"/> + <_BuiltPackages Include="$(PackagesOutput)/*.nupkg" Exclude="$(PackagesOutput)/*.symbols.nupkg"/> - - - - - + - - - - - - - $(LocalNuGetPackagesRoot)$(RepositoryName)/ - - - - - - - - + - diff --git a/src/source-build-externals/repo-projects/MSBuildLocator.proj b/src/source-build-externals/repo-projects/MSBuildLocator.proj index 2d57ef294bd..cd5d2d64d58 100644 --- a/src/source-build-externals/repo-projects/MSBuildLocator.proj +++ b/src/source-build-externals/repo-projects/MSBuildLocator.proj @@ -1,15 +1,13 @@ - - + - $(ProjectDirectory)/src/MSBuildLocator/bin/$(Configuration)/ + $(ProjectDirectory)src/MSBuildLocator/bin/$(Configuration)/ + true - - - + - $(ProjectDirectory)/src/MSBuildLocator/Microsoft.Build.Locator.csproj + $(ProjectDirectory)src/MSBuildLocator/Microsoft.Build.Locator.csproj $(BuildCommandArgs) /p:Configuration=$(Configuration) $(BuildCommandArgs) /v:$(LogVerbosity) $(BuildCommandArgs) $(RedirectRepoOutputToLog) @@ -19,17 +17,17 @@ $(BuildCommandArgs) /p:Version=$(MSBuildLocatorReleaseVersion) - - - diff --git a/src/source-build-externals/repo-projects/abstractions-xunit.proj b/src/source-build-externals/repo-projects/abstractions-xunit.proj index 01c480c8f18..28cbe0fa6fc 100644 --- a/src/source-build-externals/repo-projects/abstractions-xunit.proj +++ b/src/source-build-externals/repo-projects/abstractions-xunit.proj @@ -1,41 +1,39 @@ - - - + + + + $(ProjectDirectory)src/xunit.abstractions/bin/$(Configuration)/ + $(KeysDir)xunit.abstractions.snk + $(ProjectDirectory)global.json + true + + + - $(ProjectDirectory)/src/xunit.abstractions/bin/$(Configuration)/ - $(KeysDir)xunit.abstractions.snk + $(ProjectDirectory)xunit.abstractions.sln + $(BuildCommandArgs) /p:Configuration=$(Configuration) + $(BuildCommandArgs) /p:PackageVersion=$(AbstractionsXunitReleaseVersion) + $(BuildCommandArgs) /p:AssemblyOriginatorKeyFile=$(XunitAbstractionsKeyFilePath) + $(BuildCommandArgs) /p:DelaySign=$(DelaySign) + $(BuildCommandArgs) /p:SignAssembly=true + $(BuildCommandArgs) /p:PublicSign=$(PublicSign) + $(BuildCommandArgs) /v:$(LogVerbosity) + $(BuildCommandArgs) $(RedirectRepoOutputToLog) - - - - - - $(ProjectDirectory)/xunit.abstractions.sln - $(BuildCommandArgs) /p:Configuration=$(Configuration) - $(BuildCommandArgs) /p:PackageVersion=$(AbstractionsXunitReleaseVersion) - $(BuildCommandArgs) /p:AssemblyOriginatorKeyFile=$(XunitAbstractionsKeyFilePath) - $(BuildCommandArgs) /p:DelaySign=$(DelaySign) - $(BuildCommandArgs) /p:SignAssembly=true - $(BuildCommandArgs) /p:PublicSign=$(PublicSign) - $(BuildCommandArgs) /v:$(LogVerbosity) - $(BuildCommandArgs) $(RedirectRepoOutputToLog) - - - - - - - - - - + + + + + + + + diff --git a/src/source-build-externals/repo-projects/application-insights.proj b/src/source-build-externals/repo-projects/application-insights.proj index 3fe6a888f40..9586e2dde72 100644 --- a/src/source-build-externals/repo-projects/application-insights.proj +++ b/src/source-build-externals/repo-projects/application-insights.proj @@ -1,20 +1,18 @@ - - + - $(ProjectDirectory)/bin/$(Configuration) + $(ProjectDirectory)bin/$(Configuration) + true - - + + - - - + - $(ProjectDirectory)/BASE/src/Microsoft.ApplicationInsights/Microsoft.ApplicationInsights.csproj + $(ProjectDirectory)BASE/src/Microsoft.ApplicationInsights/Microsoft.ApplicationInsights.csproj $(BuildCommandArgs) /p:Configuration=$(Configuration) $(BuildCommandArgs) /p:StableRelease=True $(BuildCommandArgs) /p:RelativeOutputPathBase= @@ -22,22 +20,22 @@ $(BuildCommandArgs) $(RedirectRepoOutputToLog) - $(BuildCommandArgs) /p:BinRoot=$(ProjectDirectory)/bin - $(BuildCommandArgs) /p:ObjRoot=$(ProjectDirectory)/obj - $(BuildCommandArgs) /p:PackageOutputDir=$(ProjectDirectory)/bin/$(Configuration) + $(BuildCommandArgs) /p:BinRoot=$(ProjectDirectory)bin + $(BuildCommandArgs) /p:ObjRoot=$(ProjectDirectory)obj + $(BuildCommandArgs) /p:PackageOutputDir=$(ProjectDirectory)bin/$(Configuration) - - - diff --git a/src/source-build-externals/repo-projects/azure-activedirectory-identitymodel-extensions-for-dotnet.proj b/src/source-build-externals/repo-projects/azure-activedirectory-identitymodel-extensions-for-dotnet.proj index 19ffb98a88c..9f97cdc4f89 100644 --- a/src/source-build-externals/repo-projects/azure-activedirectory-identitymodel-extensions-for-dotnet.proj +++ b/src/source-build-externals/repo-projects/azure-activedirectory-identitymodel-extensions-for-dotnet.proj @@ -1,13 +1,11 @@ - - + - $(ProjectDirectory)/pack + $(ProjectDirectory)pack + true - - - + $(ProjectDirectory)src/System.IdentityModel.Tokens.Jwt/System.IdentityModel.Tokens.Jwt.csproj $(ProjectDirectory)src/Microsoft.IdentityModel.Tokens/Microsoft.IdentityModel.Tokens.csproj @@ -23,37 +21,37 @@ $(BuildCommandArgs) --output $(ProjectDirectory)pack - - - - - - - diff --git a/src/source-build-externals/repo-projects/cssparser.proj b/src/source-build-externals/repo-projects/cssparser.proj index 16822bc964b..0ff8f49ff40 100644 --- a/src/source-build-externals/repo-projects/cssparser.proj +++ b/src/source-build-externals/repo-projects/cssparser.proj @@ -1,15 +1,13 @@ - - + - $(ProjectDirectory)/src/Microsoft.Css.Parser/bin/$(Configuration)/ + $(ProjectDirectory)src/Microsoft.Css.Parser/bin/$(Configuration)/ + true - - - + - $(ProjectDirectory)/src/Microsoft.Css.Parser/Microsoft.Css.Parser.csproj + $(ProjectDirectory)src/Microsoft.Css.Parser/Microsoft.Css.Parser.csproj $(BuildCommandArgs) /p:Configuration=$(Configuration) $(BuildCommandArgs) /p:DelaySign=$(DelaySign) $(BuildCommandArgs) /p:PublicSign=$(PublicSign) @@ -18,17 +16,17 @@ $(BuildCommandArgs) $(RedirectRepoOutputToLog) - - - diff --git a/src/source-build-externals/repo-projects/docker-creds-provider.proj b/src/source-build-externals/repo-projects/docker-creds-provider.proj index 220c3c7fc9d..c6d06dd0271 100644 --- a/src/source-build-externals/repo-projects/docker-creds-provider.proj +++ b/src/source-build-externals/repo-projects/docker-creds-provider.proj @@ -1,7 +1,36 @@ - + + 2.2.4 + $(ProjectDirectory)global.json + $(ProjectDirectory)src/Valleysoft.DockerCredsProvider/bin/$(Configuration)/ + true - + + + $(ProjectDirectory)src/Valleysoft.DockerCredsProvider/Valleysoft.DockerCredsProvider.csproj + $(BuildCommandArgs) /p:Configuration=$(Configuration) + $(BuildCommandArgs) /v:$(LogVerbosity) + $(BuildCommandArgs) $(RedirectRepoOutputToLog) + $(BuildCommandArgs) /p:Version=$(DockerCredsProviderReleaseVersion) + $(BuildCommandArgs) /p:TargetFrameworks=$(NetCurrent) + + + + + + + + + diff --git a/src/source-build-externals/repo-projects/docker-creds-provider.targets b/src/source-build-externals/repo-projects/docker-creds-provider.targets deleted file mode 100644 index 52bdd1be04d..00000000000 --- a/src/source-build-externals/repo-projects/docker-creds-provider.targets +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - $(ProjectDirectory)/global.json - $(ProjectDirectory)/src/Valleysoft.DockerCredsProvider/bin/$(Configuration)/ - - - - - - - $(ProjectDirectory)/src/Valleysoft.DockerCredsProvider/Valleysoft.DockerCredsProvider.csproj - $(BuildCommandArgs) /p:Configuration=$(Configuration) - $(BuildCommandArgs) /v:$(LogVerbosity) - $(BuildCommandArgs) $(RedirectRepoOutputToLog) - $(BuildCommandArgs) /p:Version=$(DockerCredsProviderReleaseVersion) - $(BuildCommandArgs) /p:TargetFrameworks=$(NetCurrent) - - - - - - - - - - diff --git a/src/source-build-externals/repo-projects/humanizer.proj b/src/source-build-externals/repo-projects/humanizer.proj index 05276652ad9..9ae59a2bec3 100644 --- a/src/source-build-externals/repo-projects/humanizer.proj +++ b/src/source-build-externals/repo-projects/humanizer.proj @@ -1,14 +1,12 @@ - - + - $(ProjectDirectory)/src/Humanizer/bin/Release - $(ProjectDirectory)/src/NuGet.config + $(ProjectDirectory)src/Humanizer/bin/Release + $(ProjectDirectory)src/NuGet.config + true - - - + $(ProjectDirectory)src/Humanizer/Humanizer.csproj @@ -23,17 +21,17 @@ $(PackCommandArgs) /p:NuspecProperties=Version=$(HumanizerReleaseVersion) - - - diff --git a/src/source-build-externals/repo-projects/netcorecli-fsc.proj b/src/source-build-externals/repo-projects/netcorecli-fsc.proj index 16516abaca7..edcfbd0f650 100644 --- a/src/source-build-externals/repo-projects/netcorecli-fsc.proj +++ b/src/source-build-externals/repo-projects/netcorecli-fsc.proj @@ -1,8 +1,7 @@ - - + - /bl + /bl:$(ArtifactsLogRepoDir)build.binlog $(OutputArgs) /v:$(LogVerbosity) $(OutputArgs) /p:OutputPath=$(OutputPath)$(RepositoryName)/ $(OutputArgs) /p:BaseIntermediateOutputPath=$(IntermediatePath)$(RepositoryName) @@ -10,22 +9,20 @@ pack $(BuildCommandArgs) -c $(Configuration) - $(BuildCommandArgs) --output $(SourceBuiltPackagesPath) + $(BuildCommandArgs) --output $(ArtifactsShippingPackagesDir) $(BuildCommandArgs) --no-build FSharp.NET.Sdk.csproj $(BuildCommandArgs) /p:NuspecFile=FSharp.NET.Sdk.nuspec $(BuildCommandArgs) $(OutputArgs) - $(DotnetToolCommand) $(BuildCommandArgs) + $(DotNetTool) $(BuildCommandArgs) - $(SourceBuiltPackagesPath) - $(SubmoduleDirectory)$(RepositoryName)/ + $(ArtifactsShippingPackagesDir) - - + - diff --git a/src/source-build-externals/repo-projects/newtonsoft-json.proj b/src/source-build-externals/repo-projects/newtonsoft-json.proj index 4d4fab40cd6..e54a93b1434 100644 --- a/src/source-build-externals/repo-projects/newtonsoft-json.proj +++ b/src/source-build-externals/repo-projects/newtonsoft-json.proj @@ -1,39 +1,34 @@ - - - - - - - - + - $(ProjectDirectory)/Src/NuGet.Config + $(ProjectDirectory)Src/NuGet.Config $(KeysDir)Newtonsoft.Json.snk - $(ProjectDirectory)/Src/Newtonsoft.Json/ + $(ProjectDirectory)Src/Newtonsoft.Json/ $(NewtonsoftJsonDirectory)Newtonsoft.Json.csproj - /p:DotnetOnly=true - $(DotnetToolCommandArgs) /p:Configuration=$(Configuration) - $(DotnetToolCommandArgs) /p:AssemblyOriginatorKeyFile=$(NewtonsoftJsonKeyFilePath) - $(DotnetToolCommandArgs) /p:SignAssembly=true - $(DotnetToolCommandArgs) /p:PublicSign=true - $(DotnetToolCommandArgs) /p:TreatWarningsAsErrors=false - $(DotnetToolCommandArgs) /p:AdditionalConstants=SIGNED + /p:DotnetOnly=true + $(DotNetToolArgs) /p:Configuration=$(Configuration) + $(DotNetToolArgs) /p:AssemblyOriginatorKeyFile=$(NewtonsoftJsonKeyFilePath) + $(DotNetToolArgs) /p:SignAssembly=true + $(DotNetToolArgs) /p:PublicSign=true + $(DotNetToolArgs) /p:TreatWarningsAsErrors=false + $(DotNetToolArgs) /p:AdditionalConstants=SIGNED - $(DotnetToolCommand) build $(NewtonsoftJsonProjectPath) /bl:build.binlog $(DotnetToolCommandArgs) - $(DotnetToolCommand) pack $(NewtonsoftJsonProjectPath) /bl:pack.binlog $(DotnetToolCommandArgs) - $(DotnetToolCommand) clean $(NewtonsoftJsonProjectPath) $(DotnetToolCommandArgs) + $(DotNetTool) pack $(NewtonsoftJsonProjectPath) /bl:$(ArtifactsLogRepoDir)build.binlog $(DotNetToolArgs) $(NewtonsoftJsonDirectory)bin/$(Configuration)/ - - + + + + + + - diff --git a/src/source-build-externals/repo-projects/vs-solutionpersistence.proj b/src/source-build-externals/repo-projects/vs-solutionpersistence.proj index 30e11ce58d2..e00ea5cd301 100644 --- a/src/source-build-externals/repo-projects/vs-solutionpersistence.proj +++ b/src/source-build-externals/repo-projects/vs-solutionpersistence.proj @@ -1,36 +1,32 @@ - - - - - - - - - - + $(KeysDir)vs-solutionpersistence.snk - $(ProjectDirectory)/src/Microsoft.VisualStudio.SolutionPersistence/ + $(ProjectDirectory)src/Microsoft.VisualStudio.SolutionPersistence/ $(SlnPersistenceDirectory)Microsoft.VisualStudio.SolutionPersistence.csproj $(ProjectDirectory)bin/Packages/$(Configuration)/NuGet/ - $(ProjectDirectory)/global.json - $(ProjectDirectory)/nuget.config + $(ProjectDirectory)global.json + $(ProjectDirectory)nuget.config - $(DotnetToolCommandArgs) /p:Configuration=$(Configuration) - $(DotnetToolCommandArgs) /p:TreatWarningsAsErrors=false - $(DotnetToolCommandArgs) /p:AssemblyOriginatorKeyFile=$(SlnPersistenceKeyFilePath) - $(DotnetToolCommandArgs) /p:SignAssembly=true - $(DotnetToolCommandArgs) /p:PublicSign=true - $(DotnetToolCommandArgs) /p:FileVersion=$(SolutionPersistenceVersion) - $(DotnetToolCommandArgs) /p:PackageVersion=$(SolutionPersistenceVersion) + $(DotNetToolArgs) /p:Configuration=$(Configuration) + $(DotNetToolArgs) /p:TreatWarningsAsErrors=false + $(DotNetToolArgs) /p:AssemblyOriginatorKeyFile=$(SlnPersistenceKeyFilePath) + $(DotNetToolArgs) /p:SignAssembly=true + $(DotNetToolArgs) /p:PublicSign=true + $(DotNetToolArgs) /p:FileVersion=$(SolutionPersistenceVersion) + $(DotNetToolArgs) /p:PackageVersion=$(SolutionPersistenceVersion) - $(DotnetToolCommand) build $(SlnPersistenceProjectPath) /bl:build.binlog $(DotnetToolCommandArgs) - $(DotnetToolCommand) pack $(SlnPersistenceProjectPath) /bl:pack.binlog $(DotnetToolCommandArgs) - $(DotnetToolCommand) clean $(SlnPersistenceProjectPath) $(DotnetToolCommandArgs) + $(DotNetTool) pack $(SlnPersistenceProjectPath) /bl:$(ArtifactsLogRepoDir)build.binlog $(DotNetToolArgs) - + + + + + + + + diff --git a/src/source-build-externals/repo-projects/xunit.proj b/src/source-build-externals/repo-projects/xunit.proj index 0b37a85fa6a..a4c418159fa 100644 --- a/src/source-build-externals/repo-projects/xunit.proj +++ b/src/source-build-externals/repo-projects/xunit.proj @@ -1,71 +1,68 @@ - - - + + + + $(ProjectDirectory)bin/$(Configuration) + true + + + + + + + - $(ProjectDirectory)/bin/$(Configuration) + $(ProjectDirectory)xunit-notests.slnf + /p:Configuration=$(Configuration) + $(BuildCommandArgs) /p:PackageVersion=$(XunitReleaseVersion) + $(BuildCommandArgs) /p:DelaySign=$(DelaySign) + $(BuildCommandArgs) /p:PublicSign=$(PublicSign) + $(BuildCommandArgs) /v:$(LogVerbosity) + $(BuildCommandArgs) /p:PackageOutputPath=$(PackagesOutput) + $(BuildCommandArgs) $(RedirectRepoOutputToLog) - - + - - - - - - $(ProjectDirectory)/xunit-notests.slnf - /p:Configuration=$(Configuration) - $(BuildCommandArgs) /p:PackageVersion=$(XunitReleaseVersion) - $(BuildCommandArgs) /p:DelaySign=$(DelaySign) - $(BuildCommandArgs) /p:PublicSign=$(PublicSign) - $(BuildCommandArgs) /v:$(LogVerbosity) - $(BuildCommandArgs) /p:PackageOutputPath=$(PackagesOutput) - $(BuildCommandArgs) $(RedirectRepoOutputToLog) - + + - - - - + + $(ProjectDirectory)src/xunit.extensibility.execution.nuspec + - - $(ProjectDirectory)/src/xunit.extensibility.execution.nuspec - + + $(ProjectDirectory)src/xunit.extensibility.core.nuspec + + + + $(ProjectDirectory)src/xunit.runner.utility.nuspec + + + + $(ProjectDirectory)src/xunit.core.nuspec + + - - $(ProjectDirectory)/src/xunit.extensibility.core.nuspec - + - - $(ProjectDirectory)/src/xunit.runner.utility.nuspec - + - - $(ProjectDirectory)/src/xunit.core.nuspec - - - - - - - - - - - - + + + + diff --git a/src/source-build-reference-packages/azure-pipelines/templates/stages/build.yml b/src/source-build-reference-packages/azure-pipelines/templates/stages/build.yml index 2b0caeefcb8..299fda3af22 100644 --- a/src/source-build-reference-packages/azure-pipelines/templates/stages/build.yml +++ b/src/source-build-reference-packages/azure-pipelines/templates/stages/build.yml @@ -61,6 +61,5 @@ stages: dependsOn: - Linux - Windows - publishUsingPipelines: true publishAssetsImmediately: true - enablePublishBuildArtifacts: true + isAssetlessBuild: true \ No newline at end of file diff --git a/src/source-build-reference-packages/build.sh b/src/source-build-reference-packages/build.sh index a1812ac34da..346e95fcc5d 100755 --- a/src/source-build-reference-packages/build.sh +++ b/src/source-build-reference-packages/build.sh @@ -18,8 +18,4 @@ export DOTNET_CLI_TELEMETRY_OPTOUT=1 export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 export DOTNET_MULTILEVEL_LOOKUP=0 -if [[ $@ == *"DotNetBuildInnerRepo=true"* ]]; then - "$scriptroot/eng/common/build.sh" --build --restore --pack "$@" -else - "$scriptroot/eng/common/build.sh" -sb "$@" -fi +"$scriptroot/eng/common/build.sh" -sb "$@" \ No newline at end of file diff --git a/src/source-build-reference-packages/eng/Version.Details.xml b/src/source-build-reference-packages/eng/Version.Details.xml index ce600d859ec..dd72f522c41 100644 --- a/src/source-build-reference-packages/eng/Version.Details.xml +++ b/src/source-build-reference-packages/eng/Version.Details.xml @@ -1,14 +1,14 @@ - + - + https://github.com/dotnet/dotnet - 35ccf19f39389d127ab037709b8e9c5a1b111a20 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 35ccf19f39389d127ab037709b8e9c5a1b111a20 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 https://github.com/dotnet/runtime diff --git a/src/source-build-reference-packages/eng/Versions.props b/src/source-build-reference-packages/eng/Versions.props index bd230c67de8..0ef1172e14c 100644 --- a/src/source-build-reference-packages/eng/Versions.props +++ b/src/source-build-reference-packages/eng/Versions.props @@ -17,7 +17,7 @@ 6.0.0-preview.6.21352.12 6.0.0-preview.6.21352.12 - 10.0.100-preview.5.25230.108 + 10.0.100-preview.5.25251.105 1.4.13 diff --git a/src/source-build-reference-packages/eng/common/core-templates/jobs/source-build.yml b/src/source-build-reference-packages/eng/common/core-templates/jobs/source-build.yml index a10ccfbee6d..df24c948ba1 100644 --- a/src/source-build-reference-packages/eng/common/core-templates/jobs/source-build.yml +++ b/src/source-build-reference-packages/eng/common/core-templates/jobs/source-build.yml @@ -14,7 +14,7 @@ parameters: # This is the default platform provided by Arcade, intended for use by a managed-only repo. defaultManagedPlatform: name: 'Managed' - container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream9' + container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream-10-amd64' # Defines the platforms on which to run build jobs. One job is created for each platform, and the # object in this array is sent to the job template as 'platform'. If no platforms are specified, diff --git a/src/source-build-reference-packages/global.json b/src/source-build-reference-packages/global.json index 0f98c51afa3..cdad98fad97 100644 --- a/src/source-build-reference-packages/global.json +++ b/src/source-build-reference-packages/global.json @@ -3,7 +3,7 @@ "dotnet": "10.0.100-preview.3.25201.16" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25230.108", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25251.105", "Microsoft.Build.NoTargets": "3.7.0" } } diff --git a/src/source-manifest.json b/src/source-manifest.json index 3503902ec48..e5c25697f02 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -1,11 +1,11 @@ { "repositories": [ { - "packageVersion": "10.0.0-beta.25230.3", - "barId": 266426, + "packageVersion": "10.0.0-beta.25253.1", + "barId": 266741, "path": "arcade", "remoteUri": "https://github.com/dotnet/arcade", - "commitSha": "f351706234bfbdf026577122a3f2bac65eb74a5b" + "commitSha": "cdf9c563205c673b7df205e24564aa48dbc341c3" }, { "packageVersion": "8.2.2-preview.1.24521.5", @@ -15,53 +15,53 @@ "commitSha": "5fa9337a84a52e9bd185d04d156eccbdcf592f74" }, { - "packageVersion": "10.0.0-preview.5.25230.1", - "barId": 266494, + "packageVersion": "10.0.0-preview.5.25255.2", + "barId": 266892, "path": "aspnetcore", "remoteUri": "https://github.com/dotnet/aspnetcore", - "commitSha": "21ba24a7015eee34b6879b4fd2f0b94b5ff8faa6" + "commitSha": "b9112907bd7526126a355a895cce9d1ffc8bdc85" }, { - "packageVersion": "0.11.5-alpha.25251.1", - "barId": 266625, + "packageVersion": "0.11.5-alpha.25252.1", + "barId": 266716, "path": "cecil", "remoteUri": "https://github.com/dotnet/cecil", - "commitSha": "8f5ef5bf825aed91bb15039b02f7426f165b5eb8" + "commitSha": "ace481b2c118341192e9ac0caceb17cede03ed47" }, { - "packageVersion": "0.1.625104", - "barId": 266615, + "packageVersion": "0.1.625201", + "barId": 266678, "path": "command-line-api", "remoteUri": "https://github.com/dotnet/command-line-api", - "commitSha": "e5a8d8400751a0fe40f766f2130ef00c59ee9c56" + "commitSha": "c07f759f70b5517a7fefb9ac5ac73603cff49f41" }, { - "packageVersion": "9.0.0-preview.1.25251.1", - "barId": 266637, + "packageVersion": "9.0.0-preview.1.25255.1", + "barId": 266805, "path": "deployment-tools", "remoteUri": "https://github.com/dotnet/deployment-tools", - "commitSha": "150d38efe20041a832482eb69e0d61b5d795e167" + "commitSha": "6b4bb9fae2d5c2caa1c5da1b49a045239bbbae3a" }, { - "packageVersion": "9.0.623003", - "barId": 266498, + "packageVersion": "9.0.625501", + "barId": 266847, "path": "diagnostics", "remoteUri": "https://github.com/dotnet/diagnostics", - "commitSha": "c174aba9f07ab60c9dc4a68080988e5fd411afea" + "commitSha": "8a951ade8ae70e5fc47345958cf716cc8e9cffe5" }, { - "packageVersion": "10.0.0-preview.5.25251.4", - "barId": 266638, + "packageVersion": "10.0.0-preview.5.25255.1", + "barId": 266798, "path": "efcore", "remoteUri": "https://github.com/dotnet/efcore", - "commitSha": "4ff9270f21135dba86d678b8515ed2ba2e15089d" + "commitSha": "9b42f3657525ea451573d241c86d09f5b08fe6dd" }, { - "packageVersion": "10.0.0-preview.5.25224.1", - "barId": 265545, + "packageVersion": "10.0.0-preview.5.25255.1", + "barId": 266875, "path": "emsdk", "remoteUri": "https://github.com/dotnet/emsdk", - "commitSha": "90489ef36c66f4d57ddcc077429699e313eb8d05" + "commitSha": "ec33d78d8515c08b528f10ffd9da3b0ed267a89c" }, { "packageVersion": "10.0.100-beta.25224.6", @@ -71,81 +71,81 @@ "commitSha": "e8bfd3562774b2939c252d907de2f3173a2bd5bd" }, { - "packageVersion": "17.15.0-preview-25230-02", - "barId": 266376, + "packageVersion": "17.15.0-preview-25255-05", + "barId": 266818, "path": "msbuild", "remoteUri": "https://github.com/dotnet/msbuild", - "commitSha": "4775228475c3d687559252223447d94194dd0f5f" + "commitSha": "17a2cd4231cf3c198aa09d1000b4340e2f6bfd20" }, { - "packageVersion": "6.15.0-preview.1.31", - "barId": 266492, + "packageVersion": "6.15.0-preview.1.37", + "barId": 266635, "path": "nuget-client", "remoteUri": "https://github.com/nuget/nuget.client", - "commitSha": "86c695c5bdd02ca0aa735eed42508b57f695baa7" + "commitSha": "41fb88a624e61dce1fa05a5d0771b41ab7aff7a9" }, { - "packageVersion": "10.0.0-preview.25251.3", - "barId": 266611, + "packageVersion": "10.0.0-preview.25255.5", + "barId": 266919, "path": "razor", "remoteUri": "https://github.com/dotnet/razor", - "commitSha": "2e057fe832fbda6847f68d5782508d6c469d794c" + "commitSha": "d87bf4a7f18d1bdfd14cc0964acdf9b5bada301c" }, { - "packageVersion": "5.0.0-1.25230.6", - "barId": 266491, + "packageVersion": "5.0.0-1.25255.5", + "barId": 266902, "path": "roslyn", "remoteUri": "https://github.com/dotnet/roslyn", - "commitSha": "ded867328249b5a9b9e6e29e3f07abc19111f5d1" + "commitSha": "9cce7288b4f277359e40488eacc1bd8be0f81f34" }, { - "packageVersion": "10.0.0-preview.25225.1", - "barId": 265863, + "packageVersion": "10.0.0-preview.25229.1", + "barId": 266348, "path": "roslyn-analyzers", "remoteUri": "https://github.com/dotnet/roslyn-analyzers", - "commitSha": "a5c872bfda401e95a51628f961fb5abc2d182e73" + "commitSha": "ba7afc0f470c9b92b88c9468420942b2d1d57355" }, { - "packageVersion": "10.0.0-preview.5.25251.7", - "barId": 266597, + "packageVersion": "10.0.0-preview.5.25255.1", + "barId": 266819, "path": "runtime", "remoteUri": "https://github.com/dotnet/runtime", - "commitSha": "27604b57bd2e9c9aa46d005db7c4e387d461b5b6" + "commitSha": "43955cb086eb88dbe78f1764c21dd3362a2427ee" }, { "packageVersion": "10.0.0-preview.25221.1", - "barId": 266298, + "barId": 266835, "path": "scenario-tests", "remoteUri": "https://github.com/dotnet/scenario-tests", - "commitSha": "da2163776e83f86ea1259ce9e12b9ea48db6ab60" + "commitSha": "9eabbcd6e92c63e0539a649238e5a87d73f46065" }, { - "packageVersion": "10.0.100-preview.5.25251.4", - "barId": 266618, + "packageVersion": "10.0.100-preview.5.25255.3", + "barId": 266866, "path": "sdk", "remoteUri": "https://github.com/dotnet/sdk", - "commitSha": "7601b9cae2f49701609df537fe81ae73425109ed" + "commitSha": "86317d70a92223dff361e28d2874188219c7560b" }, { "packageVersion": "10.0.622801", - "barId": 266121, + "barId": 266898, "path": "source-build-externals", "remoteUri": "https://github.com/dotnet/source-build-externals", - "commitSha": "37a16c719922cb4203d0506484502fd62ac91aa7" + "commitSha": "967f0738ad131b3cb0b76b112618923780aa6048" }, { "packageVersion": "", - "barId": 266545, + "barId": 266802, "path": "source-build-reference-packages", "remoteUri": "https://github.com/dotnet/source-build-reference-packages", - "commitSha": "d1ab3b44c05f314be6885d1933d7e48fffa0cfc2" + "commitSha": "e6e60523801abc7c581434b4cd7ba1f8ee34347c" }, { - "packageVersion": "10.0.0-beta.25251.2", - "barId": 266626, + "packageVersion": "10.0.0-beta.25252.2", + "barId": 266721, "path": "sourcelink", "remoteUri": "https://github.com/dotnet/sourcelink", - "commitSha": "25716402f74dfeb1f4137601d013e158628d5196" + "commitSha": "d6ff9e72e3a48d39b19a1b2d7cbf63a0a79a6409" }, { "packageVersion": "2.2.0-beta.25228.1", @@ -155,11 +155,11 @@ "commitSha": "7f4f9c0ad18fc4dc74a906cec188adacd3847c9a" }, { - "packageVersion": "10.0.100-preview.5.25251.2", - "barId": 266636, + "packageVersion": "10.0.100-preview.5.25255.1", + "barId": 266801, "path": "templating", "remoteUri": "https://github.com/dotnet/templating", - "commitSha": "03eef3b9429ba0975982ca7427274e5986ef328e" + "commitSha": "e3f1cf05499c250de847205b51d31a5d1f7639c4" }, { "packageVersion": "17.15.0-preview-25224-01", @@ -169,25 +169,25 @@ "commitSha": "2e6d9288d3aa0269ae710844f3aa9e0a3981b26e" }, { - "packageVersion": "10.0.0-preview.5.25251.1", - "barId": 266624, + "packageVersion": "10.0.0-preview.5.25252.1", + "barId": 266720, "path": "windowsdesktop", "remoteUri": "https://github.com/dotnet/windowsdesktop", - "commitSha": "2ebb7d189eccf908c7121a5c1e5e71da0085c4dc" + "commitSha": "b88bee3ab8a7ba608d792d30c30dda3366044eec" }, { - "packageVersion": "10.0.0-preview.5.25251.4", - "barId": 266628, + "packageVersion": "10.0.0-preview.5.25255.1", + "barId": 266921, "path": "winforms", "remoteUri": "https://github.com/dotnet/winforms", - "commitSha": "43ffa433a31ca3a6af20cefadf2b13ba2a7e537d" + "commitSha": "fc5d461e63815788594bcfd7c35ace5c0958b7bc" }, { - "packageVersion": "10.0.0-preview.5.25229.1", - "barId": 266359, + "packageVersion": "10.0.0-preview.5.25255.1", + "barId": 266795, "path": "wpf", "remoteUri": "https://github.com/dotnet/wpf", - "commitSha": "53aa6f986b8c1f84cf58dbd6ea62b363f94a939d" + "commitSha": "e188e3587630e370a711fe9566a9011a7c5a181b" }, { "packageVersion": "10.0.0-preview.25228.1", diff --git a/src/sourcelink/eng/Version.Details.xml b/src/sourcelink/eng/Version.Details.xml index bcbd6374747..f35ed0578a1 100644 --- a/src/sourcelink/eng/Version.Details.xml +++ b/src/sourcelink/eng/Version.Details.xml @@ -1,6 +1,6 @@ - + https://github.com/dotnet/command-line-api @@ -8,9 +8,9 @@ - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 diff --git a/src/sourcelink/global.json b/src/sourcelink/global.json index 1b35aa1466b..cdad98fad97 100644 --- a/src/sourcelink/global.json +++ b/src/sourcelink/global.json @@ -3,7 +3,7 @@ "dotnet": "10.0.100-preview.3.25201.16" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25251.102", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25251.105", "Microsoft.Build.NoTargets": "3.7.0" } } diff --git a/src/sourcelink/src/dotnet-sourcelink/Program.cs b/src/sourcelink/src/dotnet-sourcelink/Program.cs index 319c79aebea..a929b4059d6 100644 --- a/src/sourcelink/src/dotnet-sourcelink/Program.cs +++ b/src/sourcelink/src/dotnet-sourcelink/Program.cs @@ -225,7 +225,9 @@ private async Task TestAsync(string path, AuthenticationHeaderValue? authen } }); +#pragma warning disable CA2025 // we await the tasks via WhenAll later so client can't be disposed early var tasks = documents.Where(document => document.Uri != null).Select(document => DownloadAndValidateDocumentAsync(client, document, errorReporter, cancellationToken)); +#pragma warning restore _ = await Task.WhenAll(tasks).ConfigureAwait(false); diff --git a/src/templating/eng/Version.Details.xml b/src/templating/eng/Version.Details.xml index 2e5b55b88f4..e0fc995d3d1 100644 --- a/src/templating/eng/Version.Details.xml +++ b/src/templating/eng/Version.Details.xml @@ -1,16 +1,16 @@ - + - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 diff --git a/src/templating/eng/Versions.props b/src/templating/eng/Versions.props index 902820d22c4..e8055fb786e 100644 --- a/src/templating/eng/Versions.props +++ b/src/templating/eng/Versions.props @@ -15,7 +15,7 @@ 9.0.3 - 2.0.0-beta5.25251.102 + 2.0.0-beta5.25251.105 9.0.3 9.0.3 9.0.3 diff --git a/src/templating/global.json b/src/templating/global.json index 14cdbcff382..887c8cb53a2 100644 --- a/src/templating/global.json +++ b/src/templating/global.json @@ -3,6 +3,6 @@ "dotnet": "10.0.100-preview.3.25201.16" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25251.102" + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25251.105" } } diff --git a/src/windowsdesktop/eng/Version.Details.xml b/src/windowsdesktop/eng/Version.Details.xml index ef7f11dfb06..9c37ccbd433 100644 --- a/src/windowsdesktop/eng/Version.Details.xml +++ b/src/windowsdesktop/eng/Version.Details.xml @@ -1,180 +1,180 @@ - + - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 diff --git a/src/windowsdesktop/eng/Versions.props b/src/windowsdesktop/eng/Versions.props index af998258fd0..397924a0797 100644 --- a/src/windowsdesktop/eng/Versions.props +++ b/src/windowsdesktop/eng/Versions.props @@ -8,16 +8,16 @@ false release - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-beta.25251.102 - 10.0.0-preview.5.25251.102 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-beta.25251.105 + 10.0.0-preview.5.25251.105 - 10.0.0-beta.25251.102 - 10.0.0-beta.25251.102 - 10.0.0-beta.25251.102 + 10.0.0-beta.25251.105 + 10.0.0-beta.25251.105 + 10.0.0-beta.25251.105 4.5.0 6.12.1 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 5.0.0 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 5.0.0 - 10.0.0-preview.5.25251.102 + 10.0.0-preview.5.25251.105 5.0.0 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 6.0.0 5.0.0 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 5.0.0 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 8.1.2 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 - 10.0.0-preview.5.25251.102 + 10.0.0-preview.5.25251.105 diff --git a/src/windowsdesktop/global.json b/src/windowsdesktop/global.json index 6e1ed604ffb..049a9c215e7 100644 --- a/src/windowsdesktop/global.json +++ b/src/windowsdesktop/global.json @@ -8,8 +8,8 @@ } }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25251.102", - "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25251.102", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25251.105", + "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25251.105", "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "3.4.0" } diff --git a/src/winforms/.github/workflows/labeler-build-predictor.yml b/src/winforms/.github/workflows/labeler-build-predictor.yml deleted file mode 100644 index 8a12b312db0..00000000000 --- a/src/winforms/.github/workflows/labeler-build-predictor.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: "Labeler: Build Predictor App" - -on: - # Allow dispatching the workflow via the Actions UI - workflow_dispatch: - inputs: - rebuild: - description: "Force a rebuild of the app" - type: boolean - -jobs: - build-predictor: - permissions: - actions: write - uses: dotnet/issue-labeler/.github/workflows/build-predictor.yml@f0c098669828a134c0313adf3f58c1909e555d86 # v1.0.1 - with: - rebuild: ${{ inputs.rebuild }} diff --git a/src/winforms/.github/workflows/labeler-cache-retention.yml b/src/winforms/.github/workflows/labeler-cache-retention.yml index f7561adcb0f..5df0b6c8056 100644 --- a/src/winforms/.github/workflows/labeler-cache-retention.yml +++ b/src/winforms/.github/workflows/labeler-cache-retention.yml @@ -1,13 +1,40 @@ +# Workflow template imported and updated from: +# https://github.com/dotnet/issue-labeler/wiki/Onboarding +# +# See labeler.md for more information +# +# Regularly restore the prediction models from cache to prevent cache eviction name: "Labeler: Cache Retention" +# For more information about GitHub's action cache limits and eviction policy, see: +# https://docs.github.com/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy + on: schedule: - cron: "25 20 * * *" # 20:25 every day (arbitrary time daily) workflow_dispatch: + inputs: + cache_key: + description: "The cache key suffix to use for restoring the model from cache. Defaults to 'ACTIVE'." + required: true + default: "ACTIVE" + +env: + CACHE_KEY: ${{ inputs.cache_key || 'ACTIVE' }} jobs: - cache-retention: - # Do not run the workflow on forks outside the 'dotnet' org - if: ${{ github.repository_owner == 'dotnet' }} - uses: dotnet/issue-labeler/.github/workflows/cache-retention.yml@f0c098669828a134c0313adf3f58c1909e555d86 # v1.0.1 + restore-cache: + # Do not automatically run the workflow on forks outside the 'dotnet' org + if: ${{ github.event_name == 'workflow_dispatch' || github.repository_owner == 'dotnet' }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + type: ["issues", "pulls"] + steps: + - uses: dotnet/issue-labeler/restore@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: ${{ matrix.type }} + cache_key: ${{ env.CACHE_KEY }} + fail-on-cache-miss: true diff --git a/src/winforms/.github/workflows/labeler-predict-issues.yml b/src/winforms/.github/workflows/labeler-predict-issues.yml index f1783e7340c..a12efc1512a 100644 --- a/src/winforms/.github/workflows/labeler-predict-issues.yml +++ b/src/winforms/.github/workflows/labeler-predict-issues.yml @@ -1,32 +1,60 @@ -name: "Labeler: Predict Issue Labels" +# Workflow template imported and updated from: +# https://github.com/dotnet/issue-labeler/wiki/Onboarding +# +# See labeler.md for more information +# +# Predict labels for Issues using a trained model +name: "Labeler: Predict (Issues)" on: - # Only automatically predict area labels when issues are originally opened + # Only automatically predict area labels when issues are first opened issues: types: opened # Allow dispatching the workflow via the Actions UI, specifying ranges of numbers workflow_dispatch: inputs: - issue_numbers: - description: "Issue Numbers (comma-separated list of ranges)" - type: string - model_cache_key: - description: "The cache key suffix to use for loading the model" - type: string + issues: + description: "Issue Numbers (comma-separated list of ranges)." required: true - default: "LIVE" + cache_key: + description: "The cache key suffix to use for restoring the model. Defaults to 'ACTIVE'." + required: true + default: "ACTIVE" + +env: + # Do not allow failure for jobs triggered automatically (as this causes red noise on the workflows list) + ALLOW_FAILURE: ${{ github.event_name == 'workflow_dispatch' }} + + LABEL_PREFIX: "area-" + THRESHOLD: 0.40 + DEFAULT_LABEL: "needs-area-label" jobs: - predict-issues: - # Do not run the workflow on forks outside the 'dotnet' org - if: ${{ github.repository_owner == 'dotnet' && (inputs.issue_numbers || github.event.issue.number) }} + predict-issue-label: + # Do not automatically run the workflow on forks outside the 'dotnet' org + if: ${{ github.event_name == 'workflow_dispatch' || github.repository_owner == 'dotnet' }} + runs-on: ubuntu-latest permissions: issues: write - uses: dotnet/issue-labeler/.github/workflows/predict-issues.yml@f0c098669828a134c0313adf3f58c1909e555d86 # v1.0.1 - with: - model_cache_key: ${{ inputs.model_cache_key }} - issue_numbers: ${{ inputs.issue_numbers || github.event.issue.number }} - label_prefix: "area-" - threshold: 0.40 - default_label: "needs-area-label" + steps: + - name: "Restore issues model from cache" + id: restore-model + uses: dotnet/issue-labeler/restore@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: issues + fail-on-cache-miss: ${{ env.ALLOW_FAILURE }} + quiet: true + + - name: "Predict issue labels" + id: prediction + if: ${{ steps.restore-model.outputs.cache-hit == 'true' }} + uses: dotnet/issue-labeler/predict@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + issues: ${{ inputs.issues || github.event.issue.number }} + label_prefix: ${{ env.LABEL_PREFIX }} + threshold: ${{ env.THRESHOLD }} + default_label: ${{ env.DEFAULT_LABEL }} + env: + GITHUB_TOKEN: ${{ github.token }} + continue-on-error: ${{ !env.ALLOW_FAILURE }} diff --git a/src/winforms/.github/workflows/labeler-predict-pulls.yml b/src/winforms/.github/workflows/labeler-predict-pulls.yml index 50b1f1b71ea..c25bcef0cbe 100644 --- a/src/winforms/.github/workflows/labeler-predict-pulls.yml +++ b/src/winforms/.github/workflows/labeler-predict-pulls.yml @@ -1,4 +1,10 @@ -name: "Labeler: Predict Pull Labels" +# Workflow template imported and updated from: +# https://github.com/dotnet/issue-labeler/wiki/Onboarding +# +# See labeler.md for more information +# +# Predict labels for Pull Requests using a trained model +name: "Labeler: Predict (Pulls)" on: # Per to the following documentation: @@ -13,6 +19,8 @@ on: # Only automatically predict area labels when pull requests are first opened pull_request_target: types: opened + + # Configure the branches that need to have PRs labeled branches: - 'main' - 'release/**' @@ -20,25 +28,47 @@ on: # Allow dispatching the workflow via the Actions UI, specifying ranges of numbers workflow_dispatch: inputs: - pull_numbers: - description: "Pull Numbers (comma-separated list of ranges)" - type: string - model_cache_key: - description: "The cache key suffix to use for loading the model" - type: string + pulls: + description: "Pull Request Numbers (comma-separated list of ranges)." + required: true + cache_key: + description: "The cache key suffix to use for restoring the model. Defaults to 'ACTIVE'." required: true - default: "LIVE" + default: "ACTIVE" + +env: + # Do not allow failure for jobs triggered automatically (this can block PR merge) + ALLOW_FAILURE: ${{ github.event_name == 'workflow_dispatch' }} + + LABEL_PREFIX: "area-" + THRESHOLD: 0.40 + DEFAULT_LABEL: "needs-area-label" jobs: - predict-pulls: - # Do not run the workflow on forks outside the 'dotnet' org - if: ${{ github.repository_owner == 'dotnet' && (inputs.pull_numbers || github.event.number) }} + predict-pull-label: + # Do not automatically run the workflow on forks outside the 'dotnet' org + if: ${{ github.event_name == 'workflow_dispatch' || github.repository_owner == 'dotnet' }} + runs-on: ubuntu-latest permissions: pull-requests: write - uses: dotnet/issue-labeler/.github/workflows/predict-pulls.yml@f0c098669828a134c0313adf3f58c1909e555d86 # v1.0.1 - with: - model_cache_key: ${{ inputs.model_cache_key }} - pull_numbers: ${{ inputs.pull_numbers || github.event.number }} - label_prefix: "area-" - threshold: 0.40 - default_label: "needs-area-label" + steps: + - name: "Restore pulls model from cache" + id: restore-model + uses: dotnet/issue-labeler/restore@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: pulls + fail-on-cache-miss: ${{ env.ALLOW_FAILURE }} + quiet: true + + - name: "Predict pull labels" + id: prediction + if: ${{ steps.restore-model.outputs.cache-hit == 'true' }} + uses: dotnet/issue-labeler/predict@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + pulls: ${{ inputs.pulls || github.event.number }} + label_prefix: ${{ env.LABEL_PREFIX }} + threshold: ${{ env.THRESHOLD }} + default_label: ${{ env.DEFAULT_LABEL }} + env: + GITHUB_TOKEN: ${{ github.token }} + continue-on-error: ${{ !env.ALLOW_FAILURE }} diff --git a/src/winforms/.github/workflows/labeler-promote.yml b/src/winforms/.github/workflows/labeler-promote.yml index 97f40afa8f1..c01086c5177 100644 --- a/src/winforms/.github/workflows/labeler-promote.yml +++ b/src/winforms/.github/workflows/labeler-promote.yml @@ -1,42 +1,54 @@ -name: "Labeler: Promote Models" +# Workflow template imported and updated from: +# https://github.com/dotnet/issue-labeler/wiki/Onboarding +# +# See labeler.md for more information +# +# Promote a model from staging to 'ACTIVE', backing up the currently 'ACTIVE' model +name: "Labeler: Promotion" on: # Dispatched via the Actions UI, promotes the staged models from - # a staging slot into the prediction environment + # a staged slot into the prediction environment workflow_dispatch: inputs: - promote_issues: + issues: description: "Issues: Promote Model" type: boolean required: true - promote_pulls: + pulls: description: "Pulls: Promote Model" type: boolean required: true - model_cache_key: - description: "The cache key suffix to promote into the 'LIVE' cache" - type: string + staged_key: + description: "The cache key suffix to use for promoting a staged model to 'ACTIVE'. Defaults to 'staged'." required: true - default: "staging" - backup_cache_key: - description: "The cache key suffix to use for backing up the currently promoted model" - type: string + default: "staged" + backup_key: + description: "The cache key suffix to use for backing up the currently active model. Defaults to 'backup'." default: "backup" permissions: actions: write jobs: - labeler-promote-issues: - if: ${{ inputs.promote_issues }} - uses: dotnet/issue-labeler/.github/workflows/promote-issues.yml@f0c098669828a134c0313adf3f58c1909e555d86 # v1.0.1 - with: - model_cache_key: ${{ inputs.model_cache_key }} - backup_cache_key: ${{ inputs.backup_cache_key }} + promote-issues: + if: ${{ inputs.issues }} + runs-on: ubuntu-latest + steps: + - name: "Promote Model for Issues" + uses: dotnet/issue-labeler/promote@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: "issues" + staged_key: ${{ inputs.staged_key }} + backup_key: ${{ inputs.backup_key }} - labeler-promote-pulls: - if: ${{ inputs.promote_pulls }} - uses: dotnet/issue-labeler/.github/workflows/promote-pulls.yml@f0c098669828a134c0313adf3f58c1909e555d86 # v1.0.1 - with: - model_cache_key: ${{ inputs.model_cache_key }} - backup_cache_key: ${{ inputs.backup_cache_key }} + promote-pulls: + if: ${{ inputs.pulls }} + runs-on: ubuntu-latest + steps: + - name: "Promote Model for Pull Requests" + uses: dotnet/issue-labeler/promote@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: "pulls" + staged_key: ${{ inputs.staged_key }} + backup_key: ${{ inputs.backup_key }} diff --git a/src/winforms/.github/workflows/labeler-train.yml b/src/winforms/.github/workflows/labeler-train.yml index 9775be4fe00..79ad2db0cce 100644 --- a/src/winforms/.github/workflows/labeler-train.yml +++ b/src/winforms/.github/workflows/labeler-train.yml @@ -1,60 +1,161 @@ -name: "Labeler: Train Models" +# Workflow template imported and updated from: +# https://github.com/dotnet/issue-labeler/wiki/Onboarding +# +# See labeler.md for more information +# +# Train the Issues and Pull Requests models for label prediction +name: "Labeler: Training" on: - # Dispatched via the Actions UI, stages new models for promotion consideration - # Each step of the workflow can be run independently: Download, Train, and Test workflow_dispatch: inputs: - download_issues: - description: "Issues: Download Data" - type: boolean - default: true - train_issues: - description: "Issues: Train Model" - type: boolean - default: true - test_issues: - description: "Issues: Test Model" - type: boolean - default: true - download_pulls: - description: "Pulls: Download Data" - type: boolean - default: true - train_pulls: - description: "Pulls: Train Model" - type: boolean - default: true - test_pulls: - description: "Pulls: Test Model" - type: boolean - default: true - - data_limit: - description: "Max number of items to include in the model" - type: number + type: + description: "Issues or Pull Requests" + type: choice + required: true + default: "Both" + options: + - "Both" + - "Issues" + - "Pull Requests" + steps: + description: "Training Steps" + type: choice + required: true + default: "All" + options: + - "All" + - "Download Data" + - "Train Model" + - "Test Model" + + limit: + description: "Max number of items to download for training/testing the model (newest items are used). Defaults to the max number of pages times the page size." + type: number + page_size: + description: "Number of items per page in GitHub API requests. Defaults to 100 for issues, 25 for pull requests." + type: number + page_limit: + description: "Maximum number of pages to download for training/testing the model. Defaults to 1000 for issues, 4000 for pull requests." + type: number cache_key_suffix: - description: "The cache key suffix to use for staging data/models (use 'LIVE' to bypass staging)" - type: string + description: "The cache key suffix to use for staged data/models (use 'ACTIVE' to bypass staging). Defaults to 'staged'." required: true - default: "staging" + default: "staged" + +env: + CACHE_KEY: ${{ inputs.cache_key_suffix }} + REPOSITORY: ${{ github.repository }} + LABEL_PREFIX: "area-" + THRESHOLD: "0.40" + LIMIT: ${{ inputs.limit }} + PAGE_SIZE: ${{ inputs.page_size }} + PAGE_LIMIT: ${{ inputs.page_limit }} jobs: - labeler-train: + download-issues: + if: ${{ contains(fromJSON('["Both", "Issues"]'), inputs.type) && contains(fromJSON('["All", "Download Data"]'), inputs.steps) }} + runs-on: ubuntu-latest + permissions: + issues: read + steps: + - name: "Download Issues" + uses: dotnet/issue-labeler/download@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: "issues" + cache_key: ${{ env.CACHE_KEY }} + repository: ${{ env.REPOSITORY }} + label_prefix: ${{ env.LABEL_PREFIX }} + limit: ${{ env.LIMIT }} + page_size: ${{ env.PAGE_SIZE }} + page_limit: ${{ env.PAGE_LIMIT }} + env: + GITHUB_TOKEN: ${{ github.token }} + + download-pulls: + if: ${{ contains(fromJSON('["Both", "Pull Requests"]'), inputs.type) && contains(fromJSON('["All", "Download Data"]'), inputs.steps) }} + runs-on: ubuntu-latest + permissions: + pull-requests: read + steps: + - name: "Download Pull Requests" + uses: dotnet/issue-labeler/download@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: "pulls" + cache_key: ${{ env.CACHE_KEY }} + repository: ${{ env.REPOSITORY }} + label_prefix: ${{ env.LABEL_PREFIX }} + limit: ${{ env.LIMIT }} + page_size: ${{ env.PAGE_SIZE }} + page_limit: ${{ env.PAGE_LIMIT }} + env: + GITHUB_TOKEN: ${{ github.token }} + + train-issues: + if: ${{ always() && contains(fromJSON('["Both", "Issues"]'), inputs.type) && contains(fromJSON('["All", "Train Model"]'), inputs.steps) && contains(fromJSON('["success", "skipped"]'), needs.download-issues.result) }} + runs-on: ubuntu-latest + permissions: {} + needs: download-issues + steps: + - name: "Train Model for Issues" + uses: dotnet/issue-labeler/train@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: "issues" + data_cache_key: ${{ env.CACHE_KEY }} + model_cache_key: ${{ env.CACHE_KEY }} + + train-pulls: + if: ${{ always() && contains(fromJSON('["Both", "Pull Requests"]'), inputs.type) && contains(fromJSON('["All", "Train Model"]'), inputs.steps) && contains(fromJSON('["success", "skipped"]'), needs.download-pulls.result) }} + runs-on: ubuntu-latest + permissions: {} + needs: download-pulls + steps: + - name: "Train Model for Pull Requests" + uses: dotnet/issue-labeler/train@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: "pulls" + data_cache_key: ${{ env.CACHE_KEY }} + model_cache_key: ${{ env.CACHE_KEY }} + + test-issues: + if: ${{ always() && contains(fromJSON('["Both", "Issues"]'), inputs.type) && contains(fromJSON('["All", "Test Model"]'), inputs.steps) && contains(fromJSON('["success", "skipped"]'), needs.train-issues.result) }} + runs-on: ubuntu-latest permissions: issues: read + needs: train-issues + steps: + - name: "Test Model for Issues" + uses: dotnet/issue-labeler/test@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: "issues" + cache_key: ${{ env.CACHE_KEY }} + repository: ${{ env.REPOSITORY }} + label_prefix: ${{ env.LABEL_PREFIX }} + threshold: ${{ env.THRESHOLD }} + limit: ${{ env.LIMIT }} + page_size: ${{ env.PAGE_SIZE }} + page_limit: ${{ env.PAGE_LIMIT }} + env: + GITHUB_TOKEN: ${{ github.token }} + + test-pulls: + if: ${{ always() && contains(fromJSON('["Both", "Pull Requests"]'), inputs.type) && contains(fromJSON('["All", "Test Model"]'), inputs.steps) && contains(fromJSON('["success", "skipped"]'), needs.train-pulls.result) }} + runs-on: ubuntu-latest + permissions: pull-requests: read - actions: write - uses: dotnet/issue-labeler/.github/workflows/train.yml@f0c098669828a134c0313adf3f58c1909e555d86 # v1.0.1 - with: - download_issues: ${{ inputs.download_issues }} - train_issues: ${{ inputs.train_issues }} - test_issues: ${{ inputs.test_issues }} - download_pulls: ${{ inputs.download_pulls }} - train_pulls: ${{ inputs.train_pulls }} - test_pulls: ${{ inputs.test_pulls }} - data_limit: ${{ inputs.data_limit && fromJSON(inputs.data_limit) || 0 }} - cache_key_suffix: ${{ inputs.cache_key_suffix }} - label_prefix: "area-" - threshold: 0.40 + needs: train-pulls + steps: + - name: "Test Model for Pull Requests" + uses: dotnet/issue-labeler/test@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0 + with: + type: "pulls" + cache_key: ${{ env.CACHE_KEY }} + repository: ${{ env.REPOSITORY }} + label_prefix: ${{ env.LABEL_PREFIX }} + threshold: ${{ env.THRESHOLD }} + limit: ${{ env.LIMIT }} + page_size: ${{ env.PAGE_SIZE }} + page_limit: ${{ env.PAGE_LIMIT }} + env: + GITHUB_TOKEN: ${{ github.token }} diff --git a/src/winforms/.github/workflows/labeler.md b/src/winforms/.github/workflows/labeler.md new file mode 100644 index 00000000000..fbedc1cb895 --- /dev/null +++ b/src/winforms/.github/workflows/labeler.md @@ -0,0 +1,32 @@ +# Issue-Labeler Workflows + +This repository uses actions from [dotnet/issue-labeler](https://github.com/dotnet/issue-labeler) to predict area labels for issues and pull requests. + +The following workflow templates were imported and updated from [dotnet/issue-labeler/wiki/Onboarding](https://github.com/dotnet/issue-labeler/wiki/Onboarding): + +1. `labeler-cache-retention.yml` +2. `labeler-predict-issues.yml` +3. `labeler-predict-pulls.yml` +4. `labeler-promote.yml` +5. `labeler-train.yml` + +## Repository Configuration + +Across these workflows, the following changes were made to configure the issue labeler for this repository: + +1. Set `LABEL_PREFIX` to `"area-"`: + - `labeler-predict-issues.yml` + - `labeler-predict-pulls.yml` + - `labeler-train.yml` +2. Set `DEFAULT_LABEL` to `"needs-area-label"`: + - `labeler-predict-issues.yml` + - `labeler-predict-pulls.yml` +3. Remove the `EXCLUDED_AUTHORS` value as we do not bypass labeling for any authors' issues/pulls in this repository: + - `labeler-predict-issues.yml` + - `labeler-predict-pulls.yml` +4. Update the pull request labeling branches to include `main` and `release/**`: + - `labeler-predict-pulls.yml` +5. Remove the `repository` input for training the models against another repository: + - `labeler-train.yml` +6. Update the cache retention cron schedule to an arbitrary time of day: + - `labeler-cache-retention.yml` diff --git a/src/winforms/eng/Version.Details.xml b/src/winforms/eng/Version.Details.xml index ec7ed7aeb6b..55e97b6170c 100644 --- a/src/winforms/eng/Version.Details.xml +++ b/src/winforms/eng/Version.Details.xml @@ -6,114 +6,114 @@ Note: if the Uri is a new place, you will need to add a subscription from that p And you can check these with "darc get-dependencies target-repo "winforms" --> - + - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - dab45dead83a6cf3e5fa9df1396c51e6a6b61c07 + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 diff --git a/src/winforms/eng/Versions.props b/src/winforms/eng/Versions.props index 1da93510307..3c0e9623a41 100644 --- a/src/winforms/eng/Versions.props +++ b/src/winforms/eng/Versions.props @@ -10,32 +10,32 @@ $(MajorVersion).$(MinorVersion).$(PatchVersion) false release - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 5.0.0-preview.7.20320.5 - 10.0.0-preview.5.25251.102 + 10.0.0-preview.5.25251.105 6.1.0-preview.1.24511.1 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 10.0.0-preview.5.25227.101 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 - 10.0.0-preview.5.25251.102 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 @@ -48,9 +48,9 @@ - 10.0.0-beta.25251.102 - 10.0.0-beta.25251.102 - 10.0.0-beta.25251.102 + 10.0.0-beta.25251.105 + 10.0.0-beta.25251.105 + 10.0.0-beta.25251.105 17.4.0-preview-20220707-01 diff --git a/src/winforms/global.json b/src/winforms/global.json index 2e93f0eb284..674ec60defd 100644 --- a/src/winforms/global.json +++ b/src/winforms/global.json @@ -14,11 +14,11 @@ "version": "10.0.100-preview.3.25201.16" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25251.102", - "Microsoft.DotNet.CMake.Sdk": "10.0.0-beta.25251.102", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25251.102", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25251.105", + "Microsoft.DotNet.CMake.Sdk": "10.0.0-beta.25251.105", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25251.105", "FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", - "Microsoft.NET.Sdk.IL": "10.0.0-preview.5.25251.102" + "Microsoft.NET.Sdk.IL": "10.0.0-preview.5.25251.105" }, "native-tools": { "cmake": "latest" diff --git a/src/winforms/src/System.Private.Windows.Core/tests/System.Private.Windows.Core.Tests/System/Private/Windows/Ole/ClipboardCoreTests.cs b/src/winforms/src/System.Private.Windows.Core/tests/System.Private.Windows.Core.Tests/System/Private/Windows/Ole/ClipboardCoreTests.cs index 9ebe6037bfe..94aa00ea60b 100644 --- a/src/winforms/src/System.Private.Windows.Core/tests/System.Private.Windows.Core.Tests/System/Private/Windows/Ole/ClipboardCoreTests.cs +++ b/src/winforms/src/System.Private.Windows.Core/tests/System.Private.Windows.Core.Tests/System/Private/Windows/Ole/ClipboardCoreTests.cs @@ -1,14 +1,15 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Specialized; using System.Diagnostics.CodeAnalysis; using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.System.Com; using ClipboardCore = System.Private.Windows.Ole.ClipboardCore>; -using DataObject = System.Private.Windows.Ole.TestDataObject>; using ClipboardScope = System.Private.Windows.Ole.ClipboardScope>; +using DataObject = System.Private.Windows.Ole.TestDataObject>; namespace System.Private.Windows.Ole; @@ -179,4 +180,190 @@ internal class SerializablePerson public string Name { get; set; } = "DefaultName"; public int Age { get; set; } } + + [Fact] + public void Clear_InvokeMultipleTimes_Success() + { + ClipboardCore.Clear(); + HRESULT result = ClipboardCore.TryGetData(out var data, out var original, retryTimes: 1, retryDelay: 0); + using (data) + { + result.Should().Be(HRESULT.CLIPBRD_E_BAD_DATA); + data.IsNull.Should().BeTrue(); + original.Should().BeNull(); + } + + ClipboardCore.Clear(); + result = ClipboardCore.TryGetData(out var data1, out var original1, retryTimes: 1, retryDelay: 0); + using (data1) + { + result.Should().Be(HRESULT.CLIPBRD_E_BAD_DATA); + data1.IsNull.Should().BeTrue(); + original1.Should().BeNull(); + } + } + + [Fact] + public void Contains_InvokeMultipleTimes_Success() + { + DataObject dataObject = new(); + HRESULT result = ClipboardCore.SetData(dataObject, copy: false, retryTimes: 1, retryDelay: 0); + result.Should().Be(HRESULT.S_OK); + + ClipboardCore.Clear(); + + result = ClipboardCore.GetDataObject(out var data, retryTimes: 1, retryDelay: 0); + HRESULT result2 = ClipboardCore.GetDataObject(out var data2, retryTimes: 1, retryDelay: 0); + result.Should().Be(result2); + result.Should().Be(HRESULT.CLIPBRD_E_BAD_DATA); + + data.Should().Be(data2); + data.Should().BeNull(); + } + + [Theory] + [StringWithNullData] + public void ContainsData_InvokeMultipleTimes_Success(string? format) + { + SetAndGetClipboardDataMultipleTimes(format, null!, out ITestDataObject? outData1, out ITestDataObject? outData2); + + outData1!.GetFormats().Should().BeEquivalentTo(outData2!.GetFormats()); + } + + [Theory] + [EnumData] + public void ContainsText_TextDataFormat_InvokeMultipleTimes_Success(string format) + { + SetAndGetClipboardDataMultipleTimes(format, null!, out ITestDataObject? outData1, out ITestDataObject? outData2); + + outData1!.GetFormats().Contains(format).Should().BeTrue(); + outData1!.GetFormats().Should().BeEquivalentTo(outData2!.GetFormats()); + } + + [Fact] + public void GetAudioStream_InvokeMultipleTimes_Success() + { + string testData = "WaveAudio"; + string format = DataFormatNames.WaveAudio; + SetAndGetClipboardDataMultipleTimes(format, testData, out ITestDataObject? outData1, out ITestDataObject? outData2); + + VerifyResult(testData, format, outData1, outData2); + } + + [Fact] + public void GetDataObject_InvokeMultipleTimes_Success() + { + SetAndGetClipboardDataMultipleTimes(null, null!, out ITestDataObject? outData1, out ITestDataObject? outData2); + + outData1.Should().NotBeNull(); + outData2.Should().NotBeNull(); + outData1.GetFormats().Should().BeEquivalentTo(outData2.GetFormats()); + } + + [Fact] + public void GetFileDropList_InvokeMultipleTimes_Success() + { + string testData = "FileDrop"; + string format = DataFormatNames.FileDrop; + SetAndGetClipboardDataMultipleTimes(format, testData, out ITestDataObject? outData1, out ITestDataObject? outData2); + + VerifyResult(testData, format, outData1, outData2); + } + + [Fact] + public void GetImage_InvokeMultipleTimes_Success() + { + string testData = "Bitmap"; + string format = DataFormatNames.Bitmap; + SetAndGetClipboardDataMultipleTimes(format, testData, out ITestDataObject? outData1, out ITestDataObject? outData2); + + VerifyResult(testData, format, outData1, outData2); + } + + [Fact] + public void GetText_InvokeMultipleTimes_Success() + { + string testData = "Text"; + string format = DataFormatNames.UnicodeText; + SetAndGetClipboardDataMultipleTimes(format, testData, out ITestDataObject? outData1, out ITestDataObject? outData2); + + VerifyResult(testData, format, outData1, outData2); + } + + [Theory] + [EnumData] + public void GetText_TextDataFormat_InvokeMultipleTimes_Success(string format) + { + string testData = "Text"; + SetAndGetClipboardDataMultipleTimes(format, testData, out ITestDataObject? outData1, out ITestDataObject? outData2); + + VerifyResult(testData, format, outData1, outData2); + } + + private static void SetAndGetClipboardDataMultipleTimes(string? format, string data, out ITestDataObject? outData1, out ITestDataObject? outData2) + { + DataObject dataObject = string.IsNullOrEmpty(format) ? new() : new(format, data); + HRESULT result = ClipboardCore.SetData(dataObject, copy: false, retryTimes: 1, retryDelay: 0); + result.Should().Be(HRESULT.S_OK); + + ClipboardCore.GetDataObject(out outData1, retryTimes: 1, retryDelay: 0); + ClipboardCore.GetDataObject(out outData2, retryTimes: 1, retryDelay: 0); + } + + private static void VerifyResult(string testData, string format, ITestDataObject? outData1, ITestDataObject? outData2) + { + outData1.Should().NotBeNull(); + outData2.Should().NotBeNull(); + outData1.GetDataPresent(format).Should().BeTrue(); + outData1.GetData(format, autoConvert: false).Should().Be(testData); + outData1.GetData(format, autoConvert: false).Should().Be(outData2.GetData(format, autoConvert: false)); + } + + [Fact] + public void SetData_Int_GetReturnsExpected() + { + ClipboardCore.SetData(new DataObject(SomeDataObject.Format, 1), copy: false, retryTimes: 1, retryDelay: 0); + ClipboardCore.GetDataObject(out var outData, retryTimes: 1, retryDelay: 0); + outData.Should().NotBeNull(); + outData.GetDataPresent("SomeDataObjectId").Should().BeTrue(); + outData.GetData("SomeDataObjectId").Should().Be(1); + } + + [Theory] + [InlineData("")] + [InlineData(" ")] + [InlineData("\t")] + [InlineData(null)] + public void SetData_EmptyOrWhitespaceFormat_ThrowsArgumentException(string? format) + { + Action action = () => ClipboardCore.SetData(new DataObject(format!, "data"), copy: true); + action.Should().Throw().WithParameterName("format"); + } + + [Fact] + public void SetFileDropList_NullFilePaths_ThrowsArgumentNullException() + { + Action action = () => ClipboardCore.SetFileDropList(null!); + action.Should().Throw().WithParameterName("filePaths"); + } + + [Fact] + public void SetFileDropList_EmptyFilePaths_ThrowsArgumentException() + { + Action action = static () => ClipboardCore.SetFileDropList([]); + action.Should().Throw(); + } + + [Theory] + [InlineData("")] + [InlineData("\0")] + public void SetFileDropList_InvalidFileInPaths_ThrowsArgumentException(string filePath) + { + StringCollection filePaths = + [ + filePath + ]; + Action action = () => ClipboardCore.SetFileDropList(filePaths); + action.Should().Throw(); + } } diff --git a/src/winforms/src/test/integration/DesignSurface/DesignSurfaceExt/DesignSurfaceExt.csproj b/src/winforms/src/test/integration/DesignSurface/DesignSurfaceExt/DesignSurfaceExt.csproj index d6cddb06058..5ef997c3739 100644 --- a/src/winforms/src/test/integration/DesignSurface/DesignSurfaceExt/DesignSurfaceExt.csproj +++ b/src/winforms/src/test/integration/DesignSurface/DesignSurfaceExt/DesignSurfaceExt.csproj @@ -10,12 +10,21 @@ Paolo Foti CPOL - https://www.codeproject.com/Articles/24385/Have-a-Great-DesignTime-Experience-with-a-Powerful + https://www.codeproject.com/Articles/24385/Have-a-Great-DesignTime-Experience-with-a-Powerful + + + $(DefaultItemExcludes);**/Framework/* + true false + + + + + diff --git a/src/winforms/src/test/integration/DesignSurface/Directory.Build.props b/src/winforms/src/test/integration/DesignSurface/Directory.Build.props index 7d46d99fef6..71b9577353c 100644 --- a/src/winforms/src/test/integration/DesignSurface/Directory.Build.props +++ b/src/winforms/src/test/integration/DesignSurface/Directory.Build.props @@ -1,7 +1,6 @@ - + false @@ -15,12 +14,8 @@ true true $(NetCurrent)-windows;net481 - + - - - $(DefaultItemExcludes);**/Framework/* @@ -34,10 +29,8 @@ - - + + @@ -48,9 +41,4 @@ - - - - - diff --git a/src/winforms/src/test/unit/System.Windows.Forms/System/Windows/Forms/ClipboardTests.cs b/src/winforms/src/test/unit/System.Windows.Forms/System/Windows/Forms/ClipboardTests.cs index 5f51799cf0a..1c6b09dfb2e 100644 --- a/src/winforms/src/test/unit/System.Windows.Forms/System/Windows/Forms/ClipboardTests.cs +++ b/src/winforms/src/test/unit/System.Windows.Forms/System/Windows/Forms/ClipboardTests.cs @@ -36,59 +36,6 @@ public void SetText_InvokeString_GetReturnsExpected() Clipboard.ContainsText().Should().BeTrue(); } - [WinFormsFact] - public void Clear_InvokeMultipleTimes_Success() - { - Clipboard.Clear(); - Clipboard.ContainsAudio().Should().BeFalse(); - Clipboard.ContainsData("format").Should().BeFalse(); - Clipboard.ContainsFileDropList().Should().BeFalse(); - Clipboard.ContainsImage().Should().BeFalse(); - Clipboard.ContainsText().Should().BeFalse(); - - Clipboard.Clear(); - Clipboard.ContainsAudio().Should().BeFalse(); - Clipboard.ContainsData("format").Should().BeFalse(); - Clipboard.ContainsFileDropList().Should().BeFalse(); - Clipboard.ContainsImage().Should().BeFalse(); - Clipboard.ContainsText().Should().BeFalse(); - } - - public static TheoryData> ContainsMethodsTheoryData => - [ - Clipboard.ContainsAudio, - Clipboard.ContainsFileDropList, - Clipboard.ContainsImage, - Clipboard.ContainsText - ]; - - [WinFormsTheory] - [MemberData(nameof(ContainsMethodsTheoryData))] - public void Contains_InvokeMultipleTimes_Success(Func contains) - { - Clipboard.Clear(); - bool result = contains.Invoke(); - contains.Invoke().Should().Be(result); - result.Should().BeFalse(); - } - - [WinFormsTheory] - [StringWithNullData] - public void ContainsData_InvokeMultipleTimes_Success(string format) - { - bool result = Clipboard.ContainsData(format); - Clipboard.ContainsData(format).Should().Be(result); - result.Should().BeFalse(); - } - - [WinFormsTheory] - [EnumData] - public void ContainsText_TextDataFormat_InvokeMultipleTimes_Success(TextDataFormat format) - { - bool result = Clipboard.ContainsText(format); - Clipboard.ContainsText(format).Should().Be(result); - } - [WinFormsTheory] [InvalidEnumData] public void ContainsText_InvalidFormat_ThrowsInvalidEnumArgumentException(TextDataFormat format) @@ -97,13 +44,6 @@ public void ContainsText_InvalidFormat_ThrowsInvalidEnumArgumentException(TextDa action.Should().Throw().WithParameterName("format"); } - [WinFormsFact] - public void GetAudioStream_InvokeMultipleTimes_Success() - { - Stream? result = Clipboard.GetAudioStream(); - (Clipboard.GetAudioStream() == result).Should().BeTrue(); - } - [WinFormsTheory] [InlineData(null)] [InlineData("")] @@ -116,43 +56,6 @@ public void GetData_NullOrEmptyFormat_Returns_Null(string? format) result.Should().BeNull(); } - [WinFormsFact] - public void GetDataObject_InvokeMultipleTimes_Success() - { - DataObject result1 = Clipboard.GetDataObject().Should().BeOfType().Subject; - DataObject result2 = Clipboard.GetDataObject().Should().BeOfType().Subject; - result1.GetFormats().Should().BeEquivalentTo(result2.GetFormats()); - } - - [WinFormsFact] - public void GetFileDropList_InvokeMultipleTimes_Success() - { - StringCollection result = Clipboard.GetFileDropList(); - Clipboard.GetFileDropList().Should().BeEquivalentTo(result); - } - - [WinFormsFact] - public void GetImage_InvokeMultipleTimes_Success() - { - Image? result = Clipboard.GetImage(); - Clipboard.GetImage().Should().BeEquivalentTo(result); - } - - [WinFormsFact] - public void GetText_InvokeMultipleTimes_Success() - { - string result = Clipboard.GetText(); - Clipboard.GetText().Should().Be(result); - } - - [WinFormsTheory] - [EnumData] - public void GetText_TextDataFormat_InvokeMultipleTimes_Success(TextDataFormat format) - { - string result = Clipboard.GetText(format); - Clipboard.GetText(format).Should().Be(result); - } - [WinFormsTheory] [InvalidEnumData] public void GetText_InvalidFormat_ThrowsInvalidEnumArgumentException(TextDataFormat format) diff --git a/src/wpf/eng/Version.Details.xml b/src/wpf/eng/Version.Details.xml index 6774a0062b0..69cb9d375a2 100644 --- a/src/wpf/eng/Version.Details.xml +++ b/src/wpf/eng/Version.Details.xml @@ -1,112 +1,112 @@ - + - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 https://dev.azure.com/dnceng/internal/_git/dotnet-wpf-int 462eb030906d5cfcbcbbe22126855da1073cda15 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 - + https://github.com/dotnet/dotnet - 78c5fa9a48d469a19ab5a61c16c955c1f370b5be + 3b83017bbef1dd0918f7c2f894cfd07f56bcd689 diff --git a/src/wpf/eng/Versions.props b/src/wpf/eng/Versions.props index 7884b6ad37d..1eb68036276 100644 --- a/src/wpf/eng/Versions.props +++ b/src/wpf/eng/Versions.props @@ -19,35 +19,35 @@ dotnet/winforms is handling versions for the analyzers. --> $(MajorVersion).$(MinorVersion).0.0 - 10.0.0-beta.25229.109 - 10.0.0-beta.25229.109 - 10.0.0-beta.25229.109 + 10.0.0-beta.25251.105 + 10.0.0-beta.25251.105 + 10.0.0-beta.25251.105 - 10.0.0-preview.5.25229.109 - 10.0.0-preview.5.25229.109 - 10.0.0-preview.5.25229.109 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 - 10.0.0-preview.5.25229.109 - 10.0.0-preview.5.25229.109 - 10.0.0-preview.5.25229.109 - 10.0.0-preview.5.25229.109 - 10.0.0-preview.5.25229.109 - 10.0.0-preview.5.25229.109 - 10.0.0-preview.5.25229.109 - 10.0.0-preview.5.25229.109 - 10.0.0-preview.5.25229.109 - 10.0.0-preview.5.25229.109 - 10.0.0-preview.5.25229.109 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 4.6.0-preview4.19176.11 - 10.0.0-preview.5.25229.109 - 10.0.0-preview.5.25229.109 - 10.0.0-preview.5.25229.109 - 10.0.0-preview.5.25229.109 - 10.0.0-preview.5.25229.109 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 + 10.0.0-preview.5.25251.105 @@ -61,7 +61,7 @@ 9.0.0-beta.24053.1 - 10.0.0-beta.25229.109 + 10.0.0-beta.25251.105 diff --git a/src/wpf/eng/common/core-templates/jobs/source-build.yml b/src/wpf/eng/common/core-templates/jobs/source-build.yml index a10ccfbee6d..df24c948ba1 100644 --- a/src/wpf/eng/common/core-templates/jobs/source-build.yml +++ b/src/wpf/eng/common/core-templates/jobs/source-build.yml @@ -14,7 +14,7 @@ parameters: # This is the default platform provided by Arcade, intended for use by a managed-only repo. defaultManagedPlatform: name: 'Managed' - container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream9' + container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream-10-amd64' # Defines the platforms on which to run build jobs. One job is created for each platform, and the # object in this array is sent to the job template as 'platform'. If no platforms are specified, diff --git a/src/wpf/eng/common/core-templates/steps/source-build.yml b/src/wpf/eng/common/core-templates/steps/source-build.yml index 8c88ccd7b08..c6b9ef51ac6 100644 --- a/src/wpf/eng/common/core-templates/steps/source-build.yml +++ b/src/wpf/eng/common/core-templates/steps/source-build.yml @@ -121,14 +121,3 @@ steps: continueOnError: true condition: succeededOrFailed() sbomEnabled: false # we don't need SBOM for logs - -# Manually inject component detection so that we can ignore the source build upstream cache, which contains -# a nupkg cache of input packages (a local feed). -# This path must match the upstream cache path in property 'CurrentRepoSourceBuiltNupkgCacheDir' -# in src\Microsoft.DotNet.Arcade.Sdk\tools\SourceBuild\SourceBuildArcade.targets -- template: /eng/common/core-templates/steps/component-governance.yml - parameters: - displayName: Component Detection (Exclude upstream cache) - is1ESPipeline: ${{ parameters.is1ESPipeline }} - componentGovernanceIgnoreDirectories: '$(Build.SourcesDirectory)/artifacts/sb/src/artifacts/obj/source-built-upstream-cache' - disableComponentGovernance: ${{ eq(variables['System.TeamProject'], 'public') }} diff --git a/src/wpf/global.json b/src/wpf/global.json index a371302f0d1..91210fc75fd 100644 --- a/src/wpf/global.json +++ b/src/wpf/global.json @@ -14,8 +14,8 @@ } }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25229.109", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25229.109", + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25251.105", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25251.105", "Microsoft.Build.NoTargets": "3.7.56" }, "sdk": {