Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OverloadResolutionPriorityAttribute #43

Merged
merged 1 commit into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Runtime.CompilerServices
{
/// <summary>
/// Specifies the priority of a member in overload resolution. When unspecified, the default priority is 0.
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
internal sealed class OverloadResolutionPriorityAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="OverloadResolutionPriorityAttribute"/> class.
/// </summary>
/// <param name="priority">The priority of the attributed member. Higher numbers are prioritized, lower numbers are deprioritized. 0 is the default if no attribute is present.</param>
public OverloadResolutionPriorityAttribute(int priority)
{
Priority = priority;
}

/// <summary>
/// The priority of the member.
/// </summary>
public int Priority { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Meziantou.Framework.FullPath" Version="1.0.12" />
<PackageReference Include="Microsoft.CodeAnalysis" Version="4.6.0" />
<PackageReference Include="Meziantou.Framework.FullPath" Version="1.0.13" />
<PackageReference Include="Microsoft.CodeAnalysis" Version="4.11.0" />
</ItemGroup>

<ItemGroup>
Expand Down
6 changes: 5 additions & 1 deletion Meziantou.Polyfill.Generator/PolyfillData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ public static PolyfillData Get(CSharpCompilation compilation, string content)

if (symbol.DeclaredAccessibility is Accessibility.Public or Accessibility.Internal)
{
declaredMethods.Add(DocumentationCommentId.CreateDeclarationId(symbol));
var declarationId = DocumentationCommentId.CreateDeclarationId(symbol);
if (declarationId is not null)
{
declaredMethods.Add(declarationId);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit" Version="2.5.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis" Version="4.8.0" />
<PackageReference Include="Microsoft.CodeAnalysis" Version="4.11.0" />
</ItemGroup>

<ItemGroup>
Expand Down
49 changes: 36 additions & 13 deletions Meziantou.Polyfill.SourceGenerator.Tests/UnitTest1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using System.IO.Compression;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using System.Security.Cryptography;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
Expand All @@ -13,7 +15,7 @@ namespace Meziantou.Polyfill.SourceGenerator.Tests;

public class UnitTest1
{
private const string LatestDotnetPackageVersion = "9.0.0-preview.1.24080.9";
private const string LatestDotnetPackageVersion = "9.0.0-rc.2.24473.5";

[Fact]
public void PolyfillOptions_Included()
Expand All @@ -24,7 +26,7 @@ public void PolyfillOptions_Included()

Assert.False(options.Include("T:C"));
}

[Fact]
public void PolyfillOptions_Excluded()
{
Expand Down Expand Up @@ -55,7 +57,7 @@ public async Task ExcludedPolyfill()
result = GenerateFiles("", assemblyLocations: assemblies, excludedPolyfills: "T:System.Diagnostics.CodeAnalysis.UnscopedRefAttribute");
Assert.Empty(result.GeneratorResult.GeneratedTrees.Where(t => t.FilePath.Contains("UnscopedRefAttribute")));
}

[Fact]
public async Task IncludedPolyfill_Methods()
{
Expand All @@ -72,7 +74,7 @@ public async Task IncludedPolyfill_Methods()
[Fact]
public async Task InternalsVisibleTo_DoNotRegenerateExtensionMethods()
{
var assemblies = await NuGetHelpers.GetNuGetReferences("NETStandard.Library", "2.0.3", "ref/netstandard2.0/");
var assemblies = await NuGetHelpers.GetNuGetReferences("NETStandard.Library", "2.0.3", "build/");
var tempGeneration = GenerateFiles("""[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("main")]""", assemblyName: "temp", assemblyLocations: assemblies);
Assert.Single(tempGeneration.GeneratorResult.GeneratedTrees.Where(t => t.FilePath.EndsWith("T_System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.g.cs")));
Assert.Single(tempGeneration.GeneratorResult.GeneratedTrees.Where(t => t.FilePath.EndsWith("M_System.IO.TextReader.ReadToEndAsync(System.Threading.CancellationToken).g.cs")));
Expand All @@ -90,7 +92,7 @@ public async Task GeneratedCodeCompile(PackageReference[] packages)
var assemblies = new List<string>();
foreach (var package in packages)
{
assemblies.AddRange(await NuGetHelpers.GetNuGetReferences(package.Name, package.Version, package.Path));
assemblies.AddRange(await NuGetHelpers.GetNuGetReferences(package.Name, package.Version, package.Path, package.Exclusions));
}

GenerateFiles("", assemblyLocations: assemblies.ToArray());
Expand Down Expand Up @@ -163,9 +165,13 @@ public static TheoryData<PackageReference[]> GetConfigurations()
{ new[] { new PackageReference("Microsoft.NETFramework.ReferenceAssemblies.net461", "1.0.3", ""), new PackageReference("System.Memory", "4.5.5", "lib/net461/") ,new PackageReference("System.ValueTuple", "4.5.0", "lib/net461/"), new PackageReference("System.Net.Http", "4.3.4", "lib/net46/") } },
{ new[] { new PackageReference("Microsoft.NETFramework.ReferenceAssemblies.net46", "1.0.3", "") } },
{ new[] { new PackageReference("NETStandard.Library", "2.0.3", "") } },
{ new[] { new PackageReference("NETStandard.Library", "2.0.3", ""), new PackageReference("System.ValueTuple", "4.5.0", "lib/netstandard2.0/") } },
{ new[] { new PackageReference("NETStandard.Library", "2.0.3", ""), new PackageReference("System.Memory", "4.5.5", "lib/netstandard2.0/") } },
{ new[] { new PackageReference("NETStandard.Library", "2.0.3", ""), new PackageReference("System.ValueTuple", "4.5.0", "lib/netstandard2.0/"), new PackageReference("System.Memory", "4.5.5", "lib/netstandard2.0/") } },
{ new[] { new PackageReference("NETStandard.Library", "2.0.3", ""),
new PackageReference("System.ValueTuple", "4.5.0", "lib/netstandard2.0/") } },
{ new[] { new PackageReference("NETStandard.Library", "2.0.3", ""),
new PackageReference("System.Memory", "4.5.5", "lib/netstandard2.0/") } },
{ new[] { new PackageReference("NETStandard.Library", "2.0.3", ""),
new PackageReference("System.ValueTuple", "4.5.0", "lib/netstandard2.0/"),
new PackageReference("System.Memory", "4.5.5", "lib/netstandard2.0/") } },
};
}

Expand All @@ -175,6 +181,8 @@ public sealed class PackageReference : IXunitSerializable
public string Version { get; set; }
public string Path { get; set; }

public string[]? Exclusions { get; set; }

public PackageReference()
: this("", "", "")
{
Expand All @@ -192,13 +200,15 @@ public void Deserialize(IXunitSerializationInfo info)
Name = info.GetValue<string>("Name");
Version = info.GetValue<string>("Version");
Path = info.GetValue<string>("Path");
Exclusions = info.GetValue<string[]>("Exclusions");
}

public void Serialize(IXunitSerializationInfo info)
{
info.AddValue("Name", Name);
info.AddValue("Version", Version);
info.AddValue("Path", Path);
info.AddValue("Exclusions", Exclusions);
}
}

Expand Down Expand Up @@ -276,9 +286,10 @@ private static class NuGetHelpers
{
private static readonly ConcurrentDictionary<string, Lazy<Task<string[]>>> Cache = new(StringComparer.Ordinal);

public static Task<string[]> GetNuGetReferences(string packageName, string version, string path)
public static Task<string[]> GetNuGetReferences(string packageName, string version, string path, string[]? exclusions = null)
{
var task = Cache.GetOrAdd(packageName + '@' + version + ':' + path, key =>
string key = Convert.ToBase64String(SHA256.HashData(Encoding.UTF8.GetBytes(packageName + '@' + version + ':' + path + (exclusions is null ? "" : string.Join(":", exclusions)))));
var task = Cache.GetOrAdd(key, key =>
{
return new Lazy<Task<string[]>>(Download);
});
Expand All @@ -295,13 +306,15 @@ async Task<string[]> Download()
using var stream = await httpClient.GetStreamAsync(new Uri($"https://www.nuget.org/api/v2/package/{packageName}/{version}")).ConfigureAwait(false);
using var zip = new ZipArchive(stream, ZipArchiveMode.Read);

foreach (var entry in zip.Entries.Where(file => file.FullName.StartsWith(path, StringComparison.Ordinal)))
foreach (var entry in zip.Entries)
{
entry.ExtractToFile(Path.Combine(tempFolder, entry.Name), overwrite: true);
var extractPath = Path.Combine(tempFolder, entry.FullName);
Directory.CreateDirectory(Path.GetDirectoryName(extractPath)!);
entry.ExtractToFile(extractPath, overwrite: true);
}
}

var dlls = Directory.GetFiles(tempFolder, "*.dll");
var dlls = Directory.GetFiles(tempFolder, "*.dll", SearchOption.AllDirectories);

// Filter invalid .NET assembly
var result = new List<string>();
Expand All @@ -310,6 +323,16 @@ async Task<string[]> Download()
if (Path.GetFileName(dll) == "System.EnterpriseServices.Wrapper.dll")
continue;

var relativePath = Path.GetRelativePath(tempFolder, dll).Replace('\\', '/');
if (!relativePath.StartsWith(path, StringComparison.OrdinalIgnoreCase))
continue;

if(exclusions != null)
{
if (exclusions.Any(exclusion => relativePath.StartsWith(exclusion, StringComparison.OrdinalIgnoreCase)))
continue;
}

try
{
using var stream = File.OpenRead(dll);
Expand Down
6 changes: 3 additions & 3 deletions Meziantou.Polyfill.Tests/Meziantou.Polyfill.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@

<ItemGroup>
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="System.Memory" Version="4.5.5" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="xunit" Version="2.6.5" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
1 change: 1 addition & 0 deletions Meziantou.Polyfill.Tests/UnitTest1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public void AttributesAreAvailables()
_ = new UnsupportedOSPlatformGuardAttribute("");
_ = new CollectionBuilderAttribute(typeof(string), "");
_ = new ExperimentalAttribute("test");
_ = new OverloadResolutionPriorityAttribute(1);

_ = typeof(IsExternalInit);
}
Expand Down
1 change: 1 addition & 0 deletions Meziantou.Polyfill/Internals/AllowNullAttribute.cs
Original file line number Diff line number Diff line change
@@ -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.

#pragma warning disable IDE0130 // Namespace does not match folder structure
namespace System.Diagnostics.CodeAnalysis;

/// <summary>
Expand Down
4 changes: 2 additions & 2 deletions Meziantou.Polyfill/Meziantou.Polyfill.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<Version>1.0.39</Version>
<Version>1.0.40</Version>
<TransformOnBuild>true</TransformOnBuild>

<LangVersion>preview</LangVersion>
Expand Down Expand Up @@ -36,7 +36,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Meziantou.DotNet.CodingStandard" Version="1.0.110">
<PackageReference Include="Meziantou.DotNet.CodingStandard" Version="1.0.133">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
6 changes: 4 additions & 2 deletions Meziantou.Polyfill/PolyfillGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
{
if (Environment.GetEnvironmentVariable("Meziantou_Polyfill_Debug") is "true" or "1")
{
Debugger.Launch();
Debugger.Break();
if (Debugger.Launch())
{
Debugger.Break();
}
}

var options = context.AnalyzerConfigOptionsProvider.Select((options, cancellationToken) =>
Expand Down
3 changes: 2 additions & 1 deletion Meziantou.Polyfill/PolyfillOptions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
#pragma warning disable IDE0290 // Use primary constructor
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ By default, all needed polyfills are generated. You can configure which polyfill
- `System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute`
- `System.Runtime.CompilerServices.IsExternalInit`
- `System.Runtime.CompilerServices.ModuleInitializerAttribute`
- `System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute`
- `System.Runtime.CompilerServices.RequiredMemberAttribute`
- `System.Runtime.CompilerServices.SkipLocalsInitAttribute`
- `System.Runtime.CompilerServices.TupleElementNamesAttribute`
Expand All @@ -103,7 +104,7 @@ By default, all needed polyfills are generated. You can configure which polyfill

### Methods

- `System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>.GetOrAdd<TArg>(TKey key, System.Func<TKey, TArg, TValue> valueFactory, TArg factoryArgument)`
- `System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>.GetOrAdd<TArg>(TKey key, System.Func<TKey, TArg, TValue> valueFactory, TArg factoryArgument) where TArg : allows ref struct`
- `System.Collections.Generic.CollectionExtensions.GetValueOrDefault<TKey, TValue>(this System.Collections.Generic.IReadOnlyDictionary<TKey, TValue> dictionary, TKey key)`
- `System.Collections.Generic.CollectionExtensions.GetValueOrDefault<TKey, TValue>(this System.Collections.Generic.IReadOnlyDictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)`
- `System.Collections.Generic.KeyValuePair<TKey, TValue>.Deconstruct(out TKey key, out TValue value)`
Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "9.0.100-preview.1.24101.2",
"version": "9.0.100-rc.2.24474.11",
"rollForward": "patch"
}
}
Expand Down