diff --git a/Directory.Packages.props b/Directory.Packages.props index 2e3b4ae1f740..05a1c8ee4e04 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -66,6 +66,8 @@ + + diff --git a/NuGet.config b/NuGet.config index ecf2c176d5ad..e31293220294 100644 --- a/NuGet.config +++ b/NuGet.config @@ -25,9 +25,12 @@ + + + diff --git a/eng/Signing.props b/eng/Signing.props index d21cce9aa953..bf15cbf9652e 100644 --- a/eng/Signing.props +++ b/eng/Signing.props @@ -67,7 +67,6 @@ - @@ -81,6 +80,10 @@ + + + + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 79094c4a7c9a..9b3319e19e2d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -97,43 +97,43 @@ 63a09289745da5c256e7baf5f4194a750b1ec878 - + https://github.com/dotnet/roslyn - 6b364f666a4014bc8269131ef30df18c16a83511 + 889d6fefa9e7ffb51f97ee1628856d27697c8fc9 - + https://github.com/dotnet/roslyn - 6b364f666a4014bc8269131ef30df18c16a83511 + 889d6fefa9e7ffb51f97ee1628856d27697c8fc9 - + https://github.com/dotnet/roslyn - 6b364f666a4014bc8269131ef30df18c16a83511 + 889d6fefa9e7ffb51f97ee1628856d27697c8fc9 - + https://github.com/dotnet/roslyn - 6b364f666a4014bc8269131ef30df18c16a83511 + 889d6fefa9e7ffb51f97ee1628856d27697c8fc9 - + https://github.com/dotnet/roslyn - 6b364f666a4014bc8269131ef30df18c16a83511 + 889d6fefa9e7ffb51f97ee1628856d27697c8fc9 - + https://github.com/dotnet/roslyn - 6b364f666a4014bc8269131ef30df18c16a83511 + 889d6fefa9e7ffb51f97ee1628856d27697c8fc9 - + https://github.com/dotnet/roslyn - 6b364f666a4014bc8269131ef30df18c16a83511 + 889d6fefa9e7ffb51f97ee1628856d27697c8fc9 - + https://github.com/dotnet/roslyn - 6b364f666a4014bc8269131ef30df18c16a83511 + 889d6fefa9e7ffb51f97ee1628856d27697c8fc9 - + https://github.com/dotnet/roslyn - 6b364f666a4014bc8269131ef30df18c16a83511 + 889d6fefa9e7ffb51f97ee1628856d27697c8fc9 https://github.com/dotnet/aspnetcore diff --git a/eng/Versions.props b/eng/Versions.props index ab1f888b35cb..d037f6439041 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -26,6 +26,7 @@ compiler API targeted by analyzer assemblies. This is mostly an issue on source-build as in that build mode analyzer assemblies always target the live compiler API. --> true + true 6.0.1 true 1.6.0-preview.25064.5 @@ -213,14 +214,14 @@ - 4.14.0-1.25064.9 - 4.14.0-1.25064.9 - 4.14.0-1.25064.9 - 4.14.0-1.25064.9 - 4.14.0-1.25064.9 - 4.14.0-1.25064.9 - 4.14.0-1.25064.9 - 4.14.0-1.25064.9 + 4.14.0-1.25065.2 + 4.14.0-1.25065.2 + 4.14.0-1.25065.2 + 4.14.0-1.25065.2 + 4.14.0-1.25065.2 + 4.14.0-1.25065.2 + 4.14.0-1.25065.2 + 4.14.0-1.25065.2 diff --git a/sdk.sln b/sdk.sln index 2480a90d380b..eb92cfa5f652 100644 --- a/sdk.sln +++ b/sdk.sln @@ -517,6 +517,10 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Microsoft.DotNet.HotReload. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.DotNet.HotReload.Agent.Package", "src\BuiltInTools\HotReloadAgent\Microsoft.DotNet.HotReload.Agent.Package.csproj", "{2FF79F82-60C1-349A-4726-7783D5A6D5DF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Net.Sdk.AnalyzerRedirecting", "src\Microsoft.Net.Sdk.AnalyzerRedirecting\Microsoft.Net.Sdk.AnalyzerRedirecting.csproj", "{27BBE29B-CE6F-401F-B3CF-B07DC556FAD1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Net.Sdk.AnalyzerRedirecting.Tests", "test\Microsoft.Net.Sdk.AnalyzerRedirecting.Tests\Microsoft.Net.Sdk.AnalyzerRedirecting.Tests.csproj", "{234BE46E-4AD6-485C-B0D3-E704EF504312}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -979,6 +983,14 @@ Global {2FF79F82-60C1-349A-4726-7783D5A6D5DF}.Debug|Any CPU.Build.0 = Debug|Any CPU {2FF79F82-60C1-349A-4726-7783D5A6D5DF}.Release|Any CPU.ActiveCfg = Release|Any CPU {2FF79F82-60C1-349A-4726-7783D5A6D5DF}.Release|Any CPU.Build.0 = Release|Any CPU + {27BBE29B-CE6F-401F-B3CF-B07DC556FAD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {27BBE29B-CE6F-401F-B3CF-B07DC556FAD1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {27BBE29B-CE6F-401F-B3CF-B07DC556FAD1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {27BBE29B-CE6F-401F-B3CF-B07DC556FAD1}.Release|Any CPU.Build.0 = Release|Any CPU + {234BE46E-4AD6-485C-B0D3-E704EF504312}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {234BE46E-4AD6-485C-B0D3-E704EF504312}.Debug|Any CPU.Build.0 = Debug|Any CPU + {234BE46E-4AD6-485C-B0D3-E704EF504312}.Release|Any CPU.ActiveCfg = Release|Any CPU + {234BE46E-4AD6-485C-B0D3-E704EF504312}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1159,6 +1171,8 @@ Global {8D6A9984-118D-4415-A8FA-AB1F26CF5C44} = {3FA6F1CB-295B-4414-B18F-93845917A8CD} {418B10BD-CA42-49F3-8F4A-D8CC90C8A17D} = {71A9F549-0EB6-41F9-BC16-4A6C5007FC91} {2FF79F82-60C1-349A-4726-7783D5A6D5DF} = {71A9F549-0EB6-41F9-BC16-4A6C5007FC91} + {27BBE29B-CE6F-401F-B3CF-B07DC556FAD1} = {22AB674F-ED91-4FBC-BFEE-8A1E82F9F05E} + {234BE46E-4AD6-485C-B0D3-E704EF504312} = {580D1AE7-AA8F-4912-8B76-105594E00B3B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {FB8F26CE-4DE6-433F-B32A-79183020BBD6} diff --git a/src/Installer/redist-installer/packaging/windows/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers.nuspec b/src/Installer/redist-installer/packaging/windows/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers.nuspec new file mode 100644 index 000000000000..b3a7b71cd697 --- /dev/null +++ b/src/Installer/redist-installer/packaging/windows/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers.nuspec @@ -0,0 +1,17 @@ + + + VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers + 1.0.0 + VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers + Microsoft + Microsoft + https://www.microsoft.com/net/dotnet_library_license.htm + https://github.com/dotnet/sdk + true + Analyzers and generators from the runtime and SDK for VS insertion + © Microsoft Corporation. All rights reserved. + + + + + diff --git a/src/Installer/redist-installer/redist-installer.csproj b/src/Installer/redist-installer/redist-installer.csproj index cf099e1fb6d4..3cfdbb9a7cf1 100644 --- a/src/Installer/redist-installer/redist-installer.csproj +++ b/src/Installer/redist-installer/redist-installer.csproj @@ -36,6 +36,7 @@ + diff --git a/src/Installer/redist-installer/targets/GenerateMSIs.targets b/src/Installer/redist-installer/targets/GenerateMSIs.targets index 8e024506a0d8..727292961994 100644 --- a/src/Installer/redist-installer/targets/GenerateMSIs.targets +++ b/src/Installer/redist-installer/targets/GenerateMSIs.targets @@ -27,6 +27,10 @@ $(SdkPkgSourcesRootDirectory)/VS.Redist.Common.NetCore.SdkPlaceholder.nuspec $(ArtifactsNonShippingPackagesDir)VS.Redist.Common.NetCore.SdkPlaceholder.$(Architecture).$(FullNugetVersion).nupkg + $(SdkPkgSourcesRootDirectory)/VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers.nuspec + $(ArtifactsNonShippingPackagesDir)VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers.$(FullNugetVersion).nupkg + $(ArtifactsNonShippingPackagesDir)VS.Redist.Common.Net.Core.SDK.RuntimeAnalyzers.swr + $(ArtifactsObjDir)/LightCommandPackages @@ -414,6 +418,27 @@ + + + + + + + + + diff --git a/src/Installer/redist-installer/targets/GenerateRuntimeAnalyzers.targets b/src/Installer/redist-installer/targets/GenerateRuntimeAnalyzers.targets new file mode 100644 index 000000000000..e84a36f39ce9 --- /dev/null +++ b/src/Installer/redist-installer/targets/GenerateRuntimeAnalyzers.targets @@ -0,0 +1,7 @@ + + + + $(ArtifactsBinDir)$(Configuration)\RuntimeAnalyzers + + + diff --git a/src/Layout/redist/redist.csproj b/src/Layout/redist/redist.csproj index a241ed598f77..12299134dd66 100644 --- a/src/Layout/redist/redist.csproj +++ b/src/Layout/redist/redist.csproj @@ -27,6 +27,7 @@ + diff --git a/src/Layout/redist/targets/GenerateLayout.targets b/src/Layout/redist/targets/GenerateLayout.targets index 3160feb51095..f3c22c9cdf4e 100644 --- a/src/Layout/redist/targets/GenerateLayout.targets +++ b/src/Layout/redist/targets/GenerateLayout.targets @@ -131,6 +131,13 @@ + + + + diff --git a/src/Layout/redist/targets/RuntimeAnalyzers.targets b/src/Layout/redist/targets/RuntimeAnalyzers.targets new file mode 100644 index 000000000000..093a527e5ff8 --- /dev/null +++ b/src/Layout/redist/targets/RuntimeAnalyzers.targets @@ -0,0 +1,24 @@ + + + + $(ArtifactsBinDir)redist\$(Configuration)\dotnet\ + packs\Microsoft.NetCore.App.Ref\*\analyzers + packs\Microsoft.WindowsDesktop.App.Ref\*\analyzers + packs\Microsoft.AspNetCore.App.Ref\*\analyzers + sdk\*\Sdks\Microsoft.NET.Sdk\analyzers + sdk\*\Sdks\Microsoft.NET.Sdk.Web\analyzers + + + + + + + + + + + + + + + diff --git a/src/Microsoft.Net.Sdk.AnalyzerRedirecting/AnalyzerRedirectingPackage.cs b/src/Microsoft.Net.Sdk.AnalyzerRedirecting/AnalyzerRedirectingPackage.cs new file mode 100644 index 000000000000..8a4a84e9fc81 --- /dev/null +++ b/src/Microsoft.Net.Sdk.AnalyzerRedirecting/AnalyzerRedirectingPackage.cs @@ -0,0 +1,6 @@ +using Microsoft.VisualStudio.Shell; + +namespace Microsoft.Net.Sdk.AnalyzerRedirecting; + +[Guid("ef89a321-14da-4de4-8f71-9bf1feea15aa")] +public sealed class AnalyzerRedirectingPackage : AsyncPackage; diff --git a/src/Microsoft.Net.Sdk.AnalyzerRedirecting/Microsoft.Net.Sdk.AnalyzerRedirecting.csproj b/src/Microsoft.Net.Sdk.AnalyzerRedirecting/Microsoft.Net.Sdk.AnalyzerRedirecting.csproj new file mode 100644 index 000000000000..0b05a215c785 --- /dev/null +++ b/src/Microsoft.Net.Sdk.AnalyzerRedirecting/Microsoft.Net.Sdk.AnalyzerRedirecting.csproj @@ -0,0 +1,43 @@ + + + + + + net472 + enable + + false + true + + + RoslynDev + true + true + true + true + false + 42.42.42.4242424 + false + + + + + + + + + + + + + + + $(VersionPrefix).$(VersionSuffixDateStamp)$(VersionSuffixBuildOfTheDayPadded) + + + + + + + + diff --git a/src/Microsoft.Net.Sdk.AnalyzerRedirecting/SdkAnalyzerAssemblyRedirector.cs b/src/Microsoft.Net.Sdk.AnalyzerRedirecting/SdkAnalyzerAssemblyRedirector.cs new file mode 100644 index 000000000000..c81a829990c2 --- /dev/null +++ b/src/Microsoft.Net.Sdk.AnalyzerRedirecting/SdkAnalyzerAssemblyRedirector.cs @@ -0,0 +1,137 @@ +// 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.Immutable; +using System.ComponentModel.Composition; +using Microsoft.CodeAnalysis.Workspaces.AnalyzerRedirecting; + +// Example: +// FullPath: "C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.8\analyzers\dotnet\System.Windows.Forms.Analyzers.dll" +// ProductVersion: "8.0.8" +// PathSuffix: "analyzers\dotnet" +using AnalyzerInfo = (string FullPath, string ProductVersion, string PathSuffix); + +namespace Microsoft.Net.Sdk.AnalyzerRedirecting; + +[Export(typeof(IAnalyzerAssemblyRedirector))] +public sealed class SdkAnalyzerAssemblyRedirector : IAnalyzerAssemblyRedirector +{ + private readonly string? _insertedAnalyzersDirectory; + + /// + /// Map from analyzer assembly name (file name without extension) to a list of matching analyzers. + /// + private readonly ImmutableDictionary> _analyzerMap; + + [ImportingConstructor] + public SdkAnalyzerAssemblyRedirector() + : this(Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"..\..\DotNetRuntimeAnalyzers"))) { } + + // Internal for testing. + internal SdkAnalyzerAssemblyRedirector(string? insertedAnalyzersDirectory) + { + _insertedAnalyzersDirectory = insertedAnalyzersDirectory; + _analyzerMap = CreateAnalyzerMap(); + } + + private ImmutableDictionary> CreateAnalyzerMap() + { + var builder = ImmutableDictionary.CreateBuilder>(StringComparer.OrdinalIgnoreCase); + + // Expects layout like: + // VsInstallDir\SDK\RuntimeAnalyzers\WindowsDesktopAnalyzers\8.0.8\analyzers\dotnet\System.Windows.Forms.Analyzers.dll + // ~~~~~~~~~~~~~~~~~~~~~~~ = topLevelDirectory + // ~~~~~ = versionDirectory + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ = analyzerPath + + foreach (string topLevelDirectory in Directory.EnumerateDirectories(_insertedAnalyzersDirectory)) + { + foreach (string versionDirectory in Directory.EnumerateDirectories(topLevelDirectory)) + { + foreach (string analyzerPath in Directory.EnumerateFiles(versionDirectory, "*.dll", SearchOption.AllDirectories)) + { + if (!analyzerPath.StartsWith(versionDirectory, StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + string version = Path.GetFileName(versionDirectory); + string analyzerName = Path.GetFileNameWithoutExtension(analyzerPath); + string pathSuffix = analyzerPath.Substring(versionDirectory.Length + 1 /* slash */); + pathSuffix = Path.GetDirectoryName(pathSuffix); + + AnalyzerInfo analyzer = new() { FullPath = analyzerPath, ProductVersion = version, PathSuffix = pathSuffix }; + + if (builder.TryGetValue(analyzerName, out var existing)) + { + existing.Add(analyzer); + } + else + { + builder.Add(analyzerName, [analyzer]); + } + } + } + } + + return builder.ToImmutable(); + } + + public string? RedirectPath(string fullPath) + { + if (_analyzerMap.TryGetValue(Path.GetFileNameWithoutExtension(fullPath), out var analyzers)) + { + foreach (AnalyzerInfo analyzer in analyzers) + { + var directoryPath = Path.GetDirectoryName(fullPath); + + // Note that both paths we compare here are normalized via netfx's Path.GetDirectoryName. + if (directoryPath.EndsWith(analyzer.PathSuffix, StringComparison.OrdinalIgnoreCase) && + majorAndMinorVersionsMatch(directoryPath, analyzer.PathSuffix, analyzer.ProductVersion)) + { + return analyzer.FullPath; + } + } + } + + return null; + + static bool majorAndMinorVersionsMatch(string directoryPath, string pathSuffix, string version) + { + // Find the version number in the directory path - it is in the directory name before the path suffix. + // Example: + // "C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\8.0.8\analyzers\dotnet\" = directoryPath + // ~~~~~~~~~~~~~~~~ = pathSuffix + // ~~~~~ = directoryPathVersion + // This can match also a NuGet package because the version number is at the same position: + // "C:\.nuget\packages\Microsoft.WindowsDesktop.App.Ref\8.0.8\analyzers\dotnet\" + + int index = directoryPath.LastIndexOf(pathSuffix, StringComparison.OrdinalIgnoreCase); + if (index < 0) + { + return false; + } + + string directoryPathVersion = Path.GetFileName(Path.GetDirectoryName(directoryPath.Substring(0, index))); + + return areVersionMajorMinorPartEqual(directoryPathVersion, version); + } + + static bool areVersionMajorMinorPartEqual(string version1, string version2) + { + int firstDotIndex = version1.IndexOf('.'); + if (firstDotIndex < 0) + { + return false; + } + + int secondDotIndex = version1.IndexOf('.', firstDotIndex + 1); + if (secondDotIndex < 0) + { + return false; + } + + return 0 == string.Compare(version1, 0, version2, 0, secondDotIndex, StringComparison.OrdinalIgnoreCase); + } + } +} diff --git a/src/Microsoft.Net.Sdk.AnalyzerRedirecting/source.extension.vsixmanifest b/src/Microsoft.Net.Sdk.AnalyzerRedirecting/source.extension.vsixmanifest new file mode 100644 index 000000000000..3c3150875aab --- /dev/null +++ b/src/Microsoft.Net.Sdk.AnalyzerRedirecting/source.extension.vsixmanifest @@ -0,0 +1,23 @@ + + + + + .NET SDK Analyzer Redirecting + .NET SDK Analyzer Redirecting Package. + + + + + + + + + + + + + + amd64 + + + diff --git a/src/Tasks/sdk-tasks/GenerateRuntimeAnalyzersSWR.cs b/src/Tasks/sdk-tasks/GenerateRuntimeAnalyzersSWR.cs new file mode 100644 index 000000000000..7131a5fc83dc --- /dev/null +++ b/src/Tasks/sdk-tasks/GenerateRuntimeAnalyzersSWR.cs @@ -0,0 +1,134 @@ +// 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. + +namespace Microsoft.DotNet.Cli.Build +{ + public class GenerateRuntimeAnalyzersSWR : Task + { + [Required] + public string RuntimeAnalyzersLayoutDirectory { get; set; } + + [Required] + public string OutputFile { get; set; } + + public override bool Execute() + { + StringBuilder sb = new StringBuilder(SWR_HEADER); + + // NOTE: Keep in sync with SdkAnalyzerAssemblyRedirector. + // This is intentionally short to avoid long path problems. + const string installDir = @"DotNetRuntimeAnalyzers"; + + AddFolder(sb, + @"AnalyzerRedirecting", + @"Common7\IDE\CommonExtensions\Microsoft\AnalyzerRedirecting", + filesToInclude: + [ + "Microsoft.Net.Sdk.AnalyzerRedirecting.dll", + "Microsoft.Net.Sdk.AnalyzerRedirecting.pkgdef", + "extension.vsixmanifest", + ]); + + AddFolder(sb, + @"AspNetCoreAnalyzers", + @$"{installDir}\AspNetCoreAnalyzers"); + + AddFolder(sb, + @"NetCoreAnalyzers", + @$"{installDir}\NetCoreAnalyzers"); + + AddFolder(sb, + @"WindowsDesktopAnalyzers", + @$"{installDir}\WindowsDesktopAnalyzers"); + + AddFolder(sb, + @"SDKAnalyzers", + @$"{installDir}\SDKAnalyzers"); + + AddFolder(sb, + @"WebSDKAnalyzers", + @$"{installDir}\WebSDKAnalyzers"); + + File.WriteAllText(OutputFile, sb.ToString()); + + return true; + } + + private void AddFolder(StringBuilder sb, string relativeSourcePath, string swrInstallDir, bool ngenAssemblies = true, IEnumerable filesToInclude = null) + { + string sourceFolder = Path.Combine(RuntimeAnalyzersLayoutDirectory, relativeSourcePath); + + // If files were specified explicitly, check that they exist. + if (filesToInclude != null) + { + foreach (var file in filesToInclude) + { + var path = Path.Combine(sourceFolder, file); + if (!File.Exists(path)) + { + throw new InvalidOperationException($"File not found: {path}"); + } + } + } + + IEnumerable files = filesToInclude ?? + Directory.GetFiles(sourceFolder) + .Where(static f => + { + var extension = Path.GetExtension(f); + return !extension.Equals(".pdb", StringComparison.OrdinalIgnoreCase) && + !extension.Equals(".swr", StringComparison.OrdinalIgnoreCase) && + !Path.GetFileName(f).Equals("_._"); + }); + + if (files.Any()) + { + sb.Append(@"folder ""InstallDir:\"); + sb.Append(swrInstallDir); + sb.AppendLine(@"\"""); + + foreach (var file in files) + { + var fileName = Path.GetFileName(file); + + sb.Append(@" file source=""$(PkgVS_Redist_Common_Net_Core_SDK_RuntimeAnalyzers)\"); + sb.Append(Path.Combine(relativeSourcePath, fileName)); + sb.Append('"'); + + if (ngenAssemblies && file.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) + { + sb.Append(@" vs.file.ngenApplications=""[installDir]\Common7\IDE\vsn.exe"""); + } + + sb.AppendLine(); + } + + sb.AppendLine(); + } + + // Don't go to sub-folders if the list of files was explicitly specified. + if (filesToInclude != null) + { + return; + } + + foreach (var subfolder in Directory.GetDirectories(sourceFolder)) + { + string subfolderName = Path.GetFileName(subfolder); + string newRelativeSourcePath = Path.Combine(relativeSourcePath, subfolderName); + string newSwrInstallDir = Path.Combine(swrInstallDir, subfolderName); + + // Don't propagate ngenAssemblies to subdirectories. + AddFolder(sb, newRelativeSourcePath, newSwrInstallDir); + } + } + + private static readonly string SWR_HEADER = @"use vs + +package name=Microsoft.Net.Core.SDK.RuntimeAnalyzers + version=$(ProductsBuildVersion) + vs.package.internalRevision=$(PackageInternalRevision) + +"; + } +} diff --git a/src/Tasks/sdk-tasks/sdk-tasks.InTree.targets b/src/Tasks/sdk-tasks/sdk-tasks.InTree.targets index d7a75eb6ce39..6f668d164f91 100644 --- a/src/Tasks/sdk-tasks/sdk-tasks.InTree.targets +++ b/src/Tasks/sdk-tasks/sdk-tasks.InTree.targets @@ -19,6 +19,7 @@ + diff --git a/test/Microsoft.Net.Sdk.AnalyzerRedirecting.Tests/Microsoft.Net.Sdk.AnalyzerRedirecting.Tests.csproj b/test/Microsoft.Net.Sdk.AnalyzerRedirecting.Tests/Microsoft.Net.Sdk.AnalyzerRedirecting.Tests.csproj new file mode 100644 index 000000000000..bae778ced676 --- /dev/null +++ b/test/Microsoft.Net.Sdk.AnalyzerRedirecting.Tests/Microsoft.Net.Sdk.AnalyzerRedirecting.Tests.csproj @@ -0,0 +1,16 @@ + + + + net472 + + + + + + + + + + + + diff --git a/test/Microsoft.Net.Sdk.AnalyzerRedirecting.Tests/SdkAnalyzerAssemblyRedirectorTests.cs b/test/Microsoft.Net.Sdk.AnalyzerRedirecting.Tests/SdkAnalyzerAssemblyRedirectorTests.cs new file mode 100644 index 000000000000..62a042d8f419 --- /dev/null +++ b/test/Microsoft.Net.Sdk.AnalyzerRedirecting.Tests/SdkAnalyzerAssemblyRedirectorTests.cs @@ -0,0 +1,68 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.Net.Sdk.AnalyzerRedirecting.Tests; + +public class SdkAnalyzerAssemblyRedirectorTests(ITestOutputHelper log) : SdkTest(log) +{ + [Theory] + [InlineData("9.0.0-preview.5.24306.11", "9.0.0-preview.7.24406.2")] + [InlineData("9.0.0-preview.5.24306.11", "9.0.1-preview.7.24406.2")] + [InlineData("9.0.100", "9.0.0-preview.7.24406.2")] + [InlineData("9.0.100", "9.0.200")] + [InlineData("9.0.100", "9.0.101")] + public void SameMajorMinorVersion(string a, string b) + { + TestDirectory testDir = _testAssetsManager.CreateTestDirectory(identifier: "RuntimeAnalyzers"); + + var vsDir = Path.Combine(testDir.Path, "vs"); + var vsAnalyzerPath = FakeDll(vsDir, @$"AspNetCoreAnalyzers\{a}\analyzers\dotnet\cs", "Microsoft.AspNetCore.App.Analyzers"); + var sdkAnalyzerPath = FakeDll(testDir.Path, @$"sdk\packs\Microsoft.AspNetCore.App.Ref\{b}\analyzers\dotnet\cs", "Microsoft.AspNetCore.App.Analyzers"); + + var resolver = new SdkAnalyzerAssemblyRedirector(vsDir); + var redirected = resolver.RedirectPath(sdkAnalyzerPath); + redirected.Should().Be(vsAnalyzerPath); + } + + [Fact] + public void DifferentPathSuffix() + { + TestDirectory testDir = _testAssetsManager.CreateTestDirectory(identifier: "RuntimeAnalyzers"); + + var vsDir = Path.Combine(testDir.Path, "vs"); + FakeDll(vsDir, @"AspNetCoreAnalyzers\9.0.0-preview.5.24306.11\analyzers\dotnet\cs", "Microsoft.AspNetCore.App.Analyzers"); + var sdkAnalyzerPath = FakeDll(testDir.Path, @"sdk\packs\Microsoft.AspNetCore.App.Ref\9.0.0-preview.7.24406.2\analyzers\dotnet\vb", "Microsoft.AspNetCore.App.Analyzers"); + + var resolver = new SdkAnalyzerAssemblyRedirector(vsDir); + var redirected = resolver.RedirectPath(sdkAnalyzerPath); + redirected.Should().BeNull(); + } + + [Theory] + [InlineData("8.0.100", "9.0.0-preview.7.24406.2")] + [InlineData("9.1.100", "9.0.0-preview.7.24406.2")] + [InlineData("9.1.0-preview.5.24306.11", "9.0.0-preview.7.24406.2")] + [InlineData("9.0.100", "9.1.100")] + [InlineData("9.0.100", "10.0.100")] + [InlineData("9.9.100", "9.10.100")] + public void DifferentMajorMinorVersion(string a, string b) + { + TestDirectory testDir = _testAssetsManager.CreateTestDirectory(identifier: "RuntimeAnalyzers"); + + var vsDir = Path.Combine(testDir.Path, "vs"); + FakeDll(vsDir, @$"AspNetCoreAnalyzers\{a}\analyzers\dotnet\cs", "Microsoft.AspNetCore.App.Analyzers"); + var sdkAnalyzerPath = FakeDll(testDir.Path, @$"sdk\packs\Microsoft.AspNetCore.App.Ref\{b}\analyzers\dotnet\cs", "Microsoft.AspNetCore.App.Analyzers"); + + var resolver = new SdkAnalyzerAssemblyRedirector(vsDir); + var redirected = resolver.RedirectPath(sdkAnalyzerPath); + redirected.Should().BeNull(); + } + + private static string FakeDll(string root, string subdir, string name) + { + var dllPath = Path.Combine(root, subdir, $"{name}.dll"); + Directory.CreateDirectory(Path.GetDirectoryName(dllPath)); + File.WriteAllText(dllPath, ""); + return dllPath; + } +} diff --git a/test/UnitTests.proj b/test/UnitTests.proj index 884a36255e87..48ce949add9d 100644 --- a/test/UnitTests.proj +++ b/test/UnitTests.proj @@ -12,7 +12,11 @@ - + + + net472 + net472 +