Skip to content

Commit faf3d4e

Browse files
authored
Properly filter assemblies compatible with the Roslyn version supported by Unity (bdovaz#255)
* Properly filter assemblies compatible with the Roslyn version supported by Unity * WIP * WIP
1 parent 9fc7ce1 commit faf3d4e

File tree

3 files changed

+137
-14
lines changed

3 files changed

+137
-14
lines changed

src/UnityNuGet.Tests/NuGetHelperTests.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,55 @@ namespace UnityNuGet.Tests
1010
{
1111
public class NuGetHelperTests
1212
{
13+
[Test]
14+
[TestCase("analyzers/dotnet/roslyn3.8/cs/Test.resources.dll")]
15+
[TestCase("analyzers/dotnet/roslyn3.8/Test.resources.dll")]
16+
[TestCase("analyzers/dotnet/cs/Test.resources.dll")]
17+
[TestCase("analyzers/dotnet/Test.resources.dll")]
18+
[TestCase("analyzers/Test.resources.dll")]
19+
public void IsApplicableAnalyzerResource_Valid(string input)
20+
{
21+
Assert.True(NuGetHelper.IsApplicableAnalyzerResource(input));
22+
}
23+
24+
[Test]
25+
[TestCase("analyzers/dotnet/roslyn3.8/vb/cs/Test.resources.dll")]
26+
[TestCase("analyzers/dotnet/roslyn3.8/cs/Test.dll")]
27+
[TestCase("analyzers/dotnet/roslyn3.8/Test.dll")]
28+
[TestCase("analyzers/dotnet/vb/Test.dll")]
29+
[TestCase("analyzers/dotnet/cs/Test.dll")]
30+
[TestCase("analyzers/dotnet/Test.dll")]
31+
[TestCase("analyzers/Test.dll")]
32+
public void IsApplicableAnalyzerResource_Invalid(string input)
33+
{
34+
Assert.False(NuGetHelper.IsApplicableAnalyzerResource(input));
35+
}
36+
37+
// Examples:
38+
// Meziantou.Analyzer -> analyzers/dotnet/roslyn3.8/cs/*
39+
// Microsoft.Unity.Analyzers -> analyzers/dotnet/cs/*
40+
// Microsoft.VisualStudio.Threading.Analyzers -> analyzers/cs/*
41+
// SonarAnalyzer.CSharp -> analyzers/*
42+
// StrongInject -> analyzers/dotnet/cs/* + analyzers/dotnet/roslyn3.8/cs/*
43+
[Test]
44+
[TestCase("analyzers/dotnet/roslyn3.8/cs/Test.dll")]
45+
[TestCase("analyzers/dotnet/roslyn3.8/Test.dll")]
46+
[TestCase("analyzers/dotnet/cs/Test.dll")]
47+
[TestCase("analyzers/dotnet/Test.dll")]
48+
[TestCase("analyzers/Test.dll")]
49+
public void IsApplicableUnitySupportedRoslynVersionFolder_Valid(string input)
50+
{
51+
Assert.True(NuGetHelper.IsApplicableUnitySupportedRoslynVersionFolder(input));
52+
}
53+
54+
[Test]
55+
[TestCase("analyzers/dotnet/roslyn4.0/cs/Test.dll")]
56+
[TestCase("analyzers/dotnet/roslyn4.0/Test.dll")]
57+
public void IsApplicableUnitySupportedRoslynVersionFolder_Invalid(string input)
58+
{
59+
Assert.False(NuGetHelper.IsApplicableUnitySupportedRoslynVersionFolder(input));
60+
}
61+
1362
[Test]
1463
public void GetCompatiblePackageDependencyGroups_SpecificSingleFramework()
1564
{

src/UnityNuGet/NuGetHelper.cs

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
4+
using System.Text.RegularExpressions;
35
using NuGet.Packaging;
46
using NuGet.Packaging.Core;
57
using NuGet.Protocol.Core.Types;
@@ -8,6 +10,69 @@ namespace UnityNuGet
810
{
911
static class NuGetHelper
1012
{
13+
// https://learn.microsoft.com/en-us/visualstudio/extensibility/roslyn-version-support
14+
private static readonly Regex roslynVersionRegex = new(@"/roslyn(\d+)\.(\d+)\.?(\d*)/");
15+
16+
// https://docs.unity3d.com/Manual/roslyn-analyzers.html
17+
private static readonly Version unityRoslynSupportedVersion = new(3, 8, 0);
18+
19+
// https://github.com/dotnet/sdk/blob/2838d93742658300698b2194882d57fd978fb168/src/Tasks/Microsoft.NET.Build.Tasks/NuGetUtils.NuGet.cs#L50
20+
public static bool IsApplicableAnalyzer(string file) => IsApplicableAnalyzer(file, "C#");
21+
22+
private static bool IsApplicableAnalyzer(string file, string projectLanguage)
23+
{
24+
// This logic is preserved from previous implementations.
25+
// See https://github.com/NuGet/Home/issues/6279#issuecomment-353696160 for possible issues with it.
26+
bool IsAnalyzer()
27+
{
28+
return file.StartsWith("analyzers", StringComparison.Ordinal)
29+
&& file.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)
30+
&& !file.EndsWith(".resources.dll", StringComparison.OrdinalIgnoreCase);
31+
}
32+
33+
bool CS() => file.Contains("/cs/", StringComparison.OrdinalIgnoreCase);
34+
bool VB() => file.Contains("/vb/", StringComparison.OrdinalIgnoreCase);
35+
36+
bool FileMatchesProjectLanguage()
37+
{
38+
return projectLanguage switch
39+
{
40+
"C#" => CS() || !VB(),
41+
"VB" => VB() || !CS(),
42+
_ => false,
43+
};
44+
}
45+
46+
return IsAnalyzer() && FileMatchesProjectLanguage();
47+
}
48+
49+
public static bool IsApplicableAnalyzerResource(string file)
50+
{
51+
bool IsResource()
52+
{
53+
return file.StartsWith("analyzers", StringComparison.Ordinal)
54+
&& file.EndsWith(".resources.dll", StringComparison.OrdinalIgnoreCase);
55+
}
56+
57+
bool CS() => file.Contains("/cs/", StringComparison.OrdinalIgnoreCase);
58+
bool VB() => file.Contains("/vb/", StringComparison.OrdinalIgnoreCase);
59+
60+
// Czech locale is cs, catch /vb/cs/
61+
return IsResource() && ((!CS() && !VB()) || (CS() && !VB()));
62+
}
63+
64+
public static bool IsApplicableUnitySupportedRoslynVersionFolder(string file)
65+
{
66+
var roslynVersionMatch = roslynVersionRegex.Match(file);
67+
68+
bool hasRoslynVersionFolder = roslynVersionMatch.Success;
69+
bool hasUnitySupportedRoslynVersionFolder = hasRoslynVersionFolder &&
70+
int.Parse(roslynVersionMatch.Groups[1].Value) == unityRoslynSupportedVersion.Major &&
71+
int.Parse(roslynVersionMatch.Groups[2].Value) == unityRoslynSupportedVersion.Minor;
72+
73+
return !hasRoslynVersionFolder || hasUnitySupportedRoslynVersionFolder;
74+
}
75+
1176
public static IEnumerable<(FrameworkSpecificGroup, RegistryTargetFramework)> GetClosestFrameworkSpecificGroups(IEnumerable<FrameworkSpecificGroup> versions, IEnumerable<RegistryTargetFramework> targetFrameworks)
1277
{
1378
var result = new List<(FrameworkSpecificGroup, RegistryTargetFramework)>();

src/UnityNuGet/RegistryCache.cs

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public class RegistryCache
3333
public static readonly bool IsRunningOnAzure = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME"));
3434

3535
// Change this version number if the content of the packages are changed by an update of this class
36-
private const string CurrentRegistryVersion = "1.7.0";
36+
private const string CurrentRegistryVersion = "1.8.0";
3737

3838
private static readonly Encoding Utf8EncodingNoBom = new UTF8Encoding(false, false);
3939
private readonly string _rootPersistentFolder;
@@ -260,7 +260,6 @@ private async Task BuildInternal()
260260
var currentVersion = packageIdentity.Version;
261261
string npmCurrentVersion = GetNpmVersion(currentVersion);
262262

263-
264263
if (packageEntry.Version == null || !packageEntry.Version.Satisfies(packageMeta.Identity.Version))
265264
{
266265
continue;
@@ -596,12 +595,11 @@ RegistryEntry packageEntry
596595
{
597596
var packageFiles = await packageReader.GetItemsAsync(PackagingConstants.Folders.Analyzers, CancellationToken.None);
598597

599-
var analyzerFiles = packageFiles.SelectMany(p => p.Items).Where(p => p.StartsWith("analyzers/dotnet/cs")).ToArray();
600-
601-
if (analyzerFiles.Length == 0)
602-
{
603-
analyzerFiles = packageFiles.SelectMany(p => p.Items).Where(p => p.StartsWith("analyzers")).ToArray();
604-
}
598+
// https://learn.microsoft.com/en-us/nuget/guides/analyzers-conventions#analyzers-path-format
599+
var analyzerFiles = packageFiles
600+
.SelectMany(p => p.Items)
601+
.Where(p => NuGetHelper.IsApplicableUnitySupportedRoslynVersionFolder(p) && (NuGetHelper.IsApplicableAnalyzer(p) || NuGetHelper.IsApplicableAnalyzerResource(p)))
602+
.ToArray();
605603

606604
var createdDirectoryList = new List<string>();
607605

@@ -640,11 +638,22 @@ RegistryEntry packageEntry
640638

641639
if (fileExtension == ".dll")
642640
{
643-
meta = UnityMeta.GetMetaForDll(
644-
GetStableGuid(identity, fileInUnityPackage),
645-
new PlatformDefinition(UnityOs.AnyOs, UnityCpu.None, isEditorConfig: false),
646-
new string[] { "RoslynAnalyzer" },
647-
Array.Empty<string>());
641+
if (NuGetHelper.IsApplicableAnalyzer(analyzerFile))
642+
{
643+
meta = UnityMeta.GetMetaForDll(
644+
GetStableGuid(identity, fileInUnityPackage),
645+
new PlatformDefinition(UnityOs.AnyOs, UnityCpu.None, isEditorConfig: false),
646+
new string[] { "RoslynAnalyzer" },
647+
Array.Empty<string>());
648+
}
649+
else
650+
{
651+
meta = UnityMeta.GetMetaForDll(
652+
GetStableGuid(identity, fileInUnityPackage),
653+
new PlatformDefinition(UnityOs.AnyOs, UnityCpu.None, isEditorConfig: false),
654+
Array.Empty<string>(),
655+
Array.Empty<string>());
656+
}
648657
}
649658
else
650659
{

0 commit comments

Comments
 (0)