Skip to content

Commit ad9242c

Browse files
committed
Avoid conflicts with multiple helper classes from multiple assemblies
Since we were adding the EmbeddedResource helper as a global, project-wide class, if multiple projects happened to use resources, collisions would start to arise, with no way to disambiguate. Since the code in the helper is actually pretty straightforward and will very likely be inlined into the IL in the end anyway, we instead just add its code as part of the resource area being emitted itself. This might result in a slightly larger assembly if there are a ton of areas, but that's a somewhat unlikely scenario. Fixes #442
1 parent 96b2aa0 commit ad9242c

File tree

3 files changed

+55
-13
lines changed

3 files changed

+55
-13
lines changed

src/SponsorLink/SponsorLink.Analyzer.Tests.targets

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77

88
<ItemGroup Condition="'$(ManagePackageVersionsCentrally)' == 'true'">
99
<PackageReference Include="Humanizer.Core" VersionOverride="2.14.1" PrivateAssets="all" Pack="false" />
10-
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.2.1" PrivateAssets="all" Pack="false" />
10+
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.4.0" PrivateAssets="all" Pack="false" />
1111
</ItemGroup>
1212

1313
<ItemGroup Condition="'$(ManagePackageVersionsCentrally)' != 'true'">
1414
<PackageReference Include="Humanizer.Core" Version="2.14.1" PrivateAssets="all" Pack="false" />
15-
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.2.1" PrivateAssets="all" Pack="false" />
15+
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.4.0" PrivateAssets="all" Pack="false" />
1616
</ItemGroup>
1717

1818
<Target Name="AddSponsorLinkAnalyzerDependencies" BeforeTargets="CoreCompile" DependsOnTargets="ResolveLockFileCopyLocalFiles">

src/ThisAssembly.Resources/CSharp.sbntxt

+53-6
Original file line numberDiff line numberDiff line change
@@ -29,27 +29,72 @@
2929
{{~ end ~}}
3030
public static partial class {{ $0.Name }}
3131
{
32+
#if DEBUG
33+
static readonly string baseDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? "";
34+
#endif
35+
3236
{{~ if $0.IsText ~}}
3337
private static string text;
3438

3539
/// <summary>
3640
/// Gets the resource as plain text.
3741
/// </summary>
38-
public static string Text =>
39-
text ??= EmbeddedResource.GetContent(@"{{ $0.Path }}");
42+
public static string Text => text ??= GetContent(@"{{ $0.Path }}");
4043
{{~ end ~}}
4144

4245
/// <summary>
4346
/// Gets the resource as a byte array.
4447
/// </summary>
45-
public static byte[] GetBytes() =>
46-
EmbeddedResource.GetBytes(@"{{ $0.Path }}");
48+
public static byte[] GetBytes() => GetBytes(@"{{ $0.Path }}");
4749

4850
/// <summary>
4951
/// Gets the resource as a stream.
5052
/// </summary>
51-
public static Stream GetStream() =>
52-
EmbeddedResource.GetStream(@"{{ $0.Path }}");
53+
public static Stream GetStream() => GetStream(@"{{ $0.Path }}");
54+
55+
/// <summary>
56+
/// Gets the content of the embedded resource at the specified relative path.
57+
/// </summary>
58+
static string GetContent(string relativePath)
59+
{
60+
using var stream = GetStream(relativePath);
61+
using var reader = new StreamReader(stream);
62+
return reader.ReadToEnd();
63+
}
64+
65+
/// <summary>
66+
/// Gets the bytes of the embedded resource at the specified relative path.
67+
/// </summary>
68+
static byte[] GetBytes(string relativePath)
69+
{
70+
using var stream = GetStream(relativePath);
71+
var bytes = new byte[stream.Length];
72+
stream.Read(bytes, 0, bytes.Length);
73+
return bytes;
74+
}
75+
76+
/// <summary>
77+
/// Gets the stream of the embedded resource at the specified relative path.
78+
/// </summary>
79+
/// <exception cref="InvalidOperationException"></exception>
80+
static Stream GetStream(string relativePath)
81+
{
82+
var baseName = Assembly.GetExecutingAssembly().GetName().Name;
83+
var resourceName = relativePath
84+
.TrimStart('.')
85+
.Replace('/', '.')
86+
.Replace('\\', '.');
87+
88+
var manifestResourceName = Assembly.GetExecutingAssembly()
89+
.GetManifestResourceNames().FirstOrDefault(x => x.EndsWith(resourceName, StringComparison.Ordinal));
90+
91+
if (string.IsNullOrEmpty(manifestResourceName))
92+
throw new InvalidOperationException($"Did not find required resource ending in '{resourceName}' in assembly '{baseName}'.");
93+
94+
return
95+
Assembly.GetExecutingAssembly().GetManifestResourceStream(manifestResourceName) ??
96+
throw new InvalidOperationException($"Did not find required resource '{manifestResourceName}' in assembly '{baseName}'.");
97+
}
5398
}
5499
{{ end }}
55100
{{ func render }}
@@ -70,6 +115,8 @@
70115

71116
using System;
72117
using System.IO;
118+
using System.Linq;
119+
using System.Reflection;
73120
{{ if Namespace }}
74121
namespace {{ Namespace }};
75122
{{~ end ~}}

src/ThisAssembly.Resources/ResourcesGenerator.cs

-5
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@ public class ResourcesGenerator : IIncrementalGenerator
1818
{
1919
public void Initialize(IncrementalGeneratorInitializationContext context)
2020
{
21-
context.RegisterPostInitializationOutput(
22-
spc => spc.AddSource(
23-
"ThisAssembly.EmbeddedResource.cs",
24-
SourceText.From(EmbeddedResource.GetContent("EmbeddedResource.cs"), Encoding.UTF8)));
25-
2621
var files = context.AdditionalTextsProvider
2722
.Combine(context.AnalyzerConfigOptionsProvider)
2823
.Where(x =>

0 commit comments

Comments
 (0)