Skip to content

Commit f6fd85d

Browse files
committed
Add support for detecting indirect metapackage reference
For example, users of ThisAssembly may install just the metapackage. The SL analyzer should check for the direct reference of its specific package (i.e. ThisAssembly.AssemblyInfo) or the metapackage. This changes `Funding.PackageId` > `PackageIds` as a hashset, emitted from potentially multi-valued (semi-colon separated) `FundingPackageId` project property. This keeps the analyzer project simple for the simple case.
1 parent b54bcf0 commit f6fd85d

4 files changed

Lines changed: 54 additions & 16 deletions

File tree

samples/dotnet/SponsorLink.Analyzer.targets

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,19 +98,34 @@
9898
<PropertyGroup>
9999
<!-- Default to Product, which is most common for single-package products (i.e. Moq) -->
100100
<FundingPackageId Condition="'$(FundingPackageId)' == ''">$(FundingProduct)</FundingPackageId>
101-
<SponsorLinkPartial>namespace Devlooped.Sponsors%3B
101+
</PropertyGroup>
102+
103+
<ItemGroup Condition="'@(FundingAnalyzerPackageId)' == ''">
104+
<FundingAnalyzerPackageId Include="$(FundingPackageId)" />
105+
</ItemGroup>
106+
<ItemGroup>
107+
<_FundingAnalyzerPackageId Include="@(FundingAnalyzerPackageId -> '&quot;%(Identity)&quot;')" />
108+
</ItemGroup>
109+
<PropertyGroup>
110+
<_FundingPackageIds>@(_FundingAnalyzerPackageId, ',')</_FundingPackageIds>
111+
</PropertyGroup>
112+
113+
<PropertyGroup>
114+
<SponsorLinkPartial>using System.Collections.Generic%3B
115+
116+
namespace Devlooped.Sponsors%3B
102117

103118
partial class SponsorLink
104119
{
105120
public partial class Funding
106121
{
107-
public const string PackageId = "$(FundingPackageId)"%3B
122+
public static HashSet&lt;string&gt; PackageIds { get%3B } = [$(_FundingPackageIds)]%3B
108123
public const string Product = "$(FundingProduct)"%3B
109124
public const string Prefix = "$(FundingPrefix)"%3B
110125
public const int Grace = $(FundingGrace)%3B
111126
}
112127
}
113-
</SponsorLinkPartial>
128+
</SponsorLinkPartial>
114129
</PropertyGroup>
115130
<WriteLinesToFile File="$(IntermediateOutputPath)SponsorLink.g.cs" Lines="$(SponsorLinkPartial)" WriteOnlyWhenDifferent="true" Overwrite="true" />
116131
<ItemGroup>

samples/dotnet/SponsorLink/SponsorLink.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,13 @@ static bool IsSponsorManifest(this AdditionalText text, AnalyzerConfigOptionsPro
9797
=> provider.GetOptions(text).TryGetValue("build_metadata.SponsorManifest.ItemType", out var itemType) &&
9898
itemType == "SponsorManifest" &&
9999
Sponsorables.ContainsKey(Path.GetFileNameWithoutExtension(text.Path));
100-
100+
101101
static bool IsSponsorableAnalyzer(this AdditionalText text, AnalyzerConfigOptionsProvider provider)
102102
=> provider.GetOptions(text) is { } options &&
103103
options.TryGetValue("build_metadata.Analyzer.ItemType", out var itemType) &&
104104
options.TryGetValue("build_metadata.Analyzer.NuGetPackageId", out var packageId) &&
105105
itemType == "Analyzer" &&
106-
packageId == Funding.PackageId;
106+
Funding.PackageIds.Contains(packageId);
107107

108108
/// <summary>
109109
/// Reads all manifests, validating their signatures.

samples/dotnet/SponsorLink/SponsorLink.csproj

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,24 +38,40 @@
3838
<None Include="..\SponsorLink.Analyzer.targets" Link="SponsorLink.Analyzer.targets" />
3939
</ItemGroup>
4040

41-
<Target Name="EmitFunding" BeforeTargets="GenerateMSBuildEditorConfigFileShouldRun" Inputs="$(MSBuildAllProjects)" Outputs="$(IntermediateOutputPath)SponsorLink.g.cs">
42-
<Warning Condition="'$(FundingPackageId)' == ''" Code="SL001" Text="Could not determine value of FundingPackageId (defaulted to PackageId). Defaulting it to FundingProduct ('$(FundingProduct)'). Make sure this matches the containing package id, or set an explicit value." />
41+
<Target Name="EmitFunding" BeforeTargets="CompileDesignTime;CoreCompile" Inputs="$(MSBuildAllProjects)" Outputs="$(IntermediateOutputPath)SponsorLink.g.cs">
42+
<Warning Condition="'$(FundingPackageId)' == ''" Code="SL001"
43+
Text="Could not determine value of FundingPackageId (defaulted to PackageId). Defaulting it to FundingProduct ('$(FundingProduct)'). Make sure this matches the containing package id, or set an explicit value." />
4344
<PropertyGroup>
4445
<!-- Default to Product, which is most common for single-package products (i.e. Moq) -->
4546
<FundingPackageId Condition="'$(FundingPackageId)' == ''">$(FundingProduct)</FundingPackageId>
46-
<SponsorLinkPartial>namespace Devlooped.Sponsors%3B
47+
</PropertyGroup>
48+
49+
<ItemGroup Condition="'@(FundingAnalyzerPackageId)' == ''">
50+
<FundingAnalyzerPackageId Include="$(FundingPackageId)" />
51+
</ItemGroup>
52+
<ItemGroup>
53+
<_FundingAnalyzerPackageId Include="@(FundingAnalyzerPackageId -> '&quot;%(Identity)&quot;')" />
54+
</ItemGroup>
55+
<PropertyGroup>
56+
<_FundingPackageIds>@(_FundingAnalyzerPackageId, ',')</_FundingPackageIds>
57+
</PropertyGroup>
58+
59+
<PropertyGroup>
60+
<SponsorLinkPartial>using System.Collections.Generic%3B
61+
62+
namespace Devlooped.Sponsors%3B
4763

4864
partial class SponsorLink
4965
{
5066
public partial class Funding
5167
{
52-
public const string PackageId = "$(FundingPackageId)"%3B
68+
public static HashSet&lt;string&gt; PackageIds { get%3B } = [$(_FundingPackageIds)]%3B
5369
public const string Product = "$(FundingProduct)"%3B
5470
public const string Prefix = "$(FundingPrefix)"%3B
5571
public const int Grace = $(FundingGrace)%3B
5672
}
5773
}
58-
</SponsorLinkPartial>
74+
</SponsorLinkPartial>
5975
</PropertyGroup>
6076
<WriteLinesToFile File="$(IntermediateOutputPath)SponsorLink.g.cs" Lines="$(SponsorLinkPartial)" WriteOnlyWhenDifferent="true" Overwrite="true" />
6177
<ItemGroup>

samples/dotnet/SponsorLink/SponsorLinkAnalyzer.cs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// <autogenerated />
22
#nullable enable
33
using System.Collections.Immutable;
4+
using System.Linq;
45
using Microsoft.CodeAnalysis;
56
using Microsoft.CodeAnalysis.Diagnostics;
67
using static Devlooped.Sponsors.SponsorLink;
@@ -42,13 +43,19 @@ public override void Initialize(AnalysisContext context)
4243
// multiple diagnostics for each project in a solution that uses the same product.
4344
ctx.RegisterCompilationEndAction(ctx =>
4445
{
45-
var prop = Funding.PackageId.Replace('.', '_');
46-
// Only report if the package is directly referenced in the project. See SL_CollectDependencies in buildTransitive\Devlooped.Sponsors.targets
47-
if (ctx.Options.AnalyzerConfigOptionsProvider.GlobalOptions.TryGetValue("build_property." + prop, out var package) &&
48-
package?.Length > 0 &&
49-
Diagnostics.Pop() is { } diagnostic)
46+
// Only report if the package is directly referenced in the project for
47+
// any of the funding packages we monitor (i.e. we could have one or more
48+
// metapackages we also consider "direct references).
49+
// See SL_CollectDependencies in buildTransitive\Devlooped.Sponsors.targets
50+
foreach (var prop in Funding.PackageIds.Select(id => id.Replace('.', '_')))
5051
{
51-
ctx.ReportDiagnostic(diagnostic);
52+
if (ctx.Options.AnalyzerConfigOptionsProvider.GlobalOptions.TryGetValue("build_property." + prop, out var package) &&
53+
package?.Length > 0 &&
54+
Diagnostics.Pop() is { } diagnostic)
55+
{
56+
ctx.ReportDiagnostic(diagnostic);
57+
break;
58+
}
5259
}
5360
});
5461
}

0 commit comments

Comments
 (0)