diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index fe08fbf5b..4565da072 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -75,6 +75,7 @@ jobs:
dotnet pack src/bunit/ -c Release --output ${{ env.NUGET_DIRECTORY }} -p:ContinuousIntegrationBuild=true -p:publicrelease=true
dotnet pack src/bunit.template/ -c Release --output ${{ env.NUGET_DIRECTORY }} -p:ContinuousIntegrationBuild=true -p:publicrelease=true
dotnet pack src/bunit.web.query/ -c release --output ${{ env.NUGET_DIRECTORY }} -p:ContinuousIntegrationBuild=true -p:publicrelease=true
+ dotnet pack src/bunit.generators/ -c release --output ${{ env.NUGET_DIRECTORY }} -p:ContinuousIntegrationBuild=true -p:publicrelease=true
# Publish the NuGet package as an artifact, so they can be used in the following jobs
- uses: actions/upload-artifact@v4
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index d164e7c3c..09a1ac5c9 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -99,6 +99,7 @@ jobs:
dotnet pack src/bunit/ -c Release --property:PackageOutputPath=${GITHUB_WORKSPACE}/packages -p:ContinuousIntegrationBuild=true -p:publicrelease=true
dotnet pack src/bunit.template/ -c Release --property:PackageOutputPath=${GITHUB_WORKSPACE}/packages -p:ContinuousIntegrationBuild=true -p:publicrelease=true
dotnet pack src/bunit.web.query/ -c Release --property:PackageOutputPath=${GITHUB_WORKSPACE}/packages -p:ContinuousIntegrationBuild=true -p:publicrelease=true
+ dotnet pack src/bunit.generators/ -c Release --property:PackageOutputPath=${GITHUB_WORKSPACE}/packages -p:ContinuousIntegrationBuild=true -p:publicrelease=true
- name: 🛠️ Upload library to NuGet.org repository
run: |
diff --git a/Directory.Packages.props b/Directory.Packages.props
index ea2bd036a..fe9b04b1f 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -101,10 +101,10 @@
-
-
-
-
+
+
+
+
diff --git a/bunit.sln b/bunit.sln
index 6561aef97..e5b5294d4 100644
--- a/bunit.sln
+++ b/bunit.sln
@@ -60,6 +60,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bunit.generators", "src\bun
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bunit.tests", "tests\bunit.tests\bunit.tests.csproj", "{56889DE7-5E66-4E9C-815B-CBCFC9961612}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bunit.generators.tests", "tests\bunit.generators.tests\bunit.generators.tests.csproj", "{D08F7F1D-74B1-4A76-86A2-94918863740C}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -96,6 +98,10 @@ Global
{56889DE7-5E66-4E9C-815B-CBCFC9961612}.Debug|Any CPU.Build.0 = Debug|Any CPU
{56889DE7-5E66-4E9C-815B-CBCFC9961612}.Release|Any CPU.ActiveCfg = Release|Any CPU
{56889DE7-5E66-4E9C-815B-CBCFC9961612}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D08F7F1D-74B1-4A76-86A2-94918863740C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D08F7F1D-74B1-4A76-86A2-94918863740C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D08F7F1D-74B1-4A76-86A2-94918863740C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D08F7F1D-74B1-4A76-86A2-94918863740C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -109,6 +115,7 @@ Global
{AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F} = {9A2B3B34-D41C-43E8-BC7D-246BEBE48D59}
{A7C6A2AA-FF8F-4ED1-8590-5324FC566059} = {9A2B3B34-D41C-43E8-BC7D-246BEBE48D59}
{56889DE7-5E66-4E9C-815B-CBCFC9961612} = {6EA09ED4-B714-4E6F-B0E1-4D987F8AE520}
+ {D08F7F1D-74B1-4A76-86A2-94918863740C} = {6EA09ED4-B714-4E6F-B0E1-4D987F8AE520}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {24106918-1C86-4769-BDA6-9C80E64CD260}
diff --git a/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/AddStubGenerator.cs b/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/AddStubGenerator.cs
index c7fadff33..a96d88980 100644
--- a/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/AddStubGenerator.cs
+++ b/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/AddStubGenerator.cs
@@ -2,6 +2,7 @@
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.CSharp; // For GetInterceptableLocation API and InterceptableLocation type
namespace Bunit.Web.Stubs.AddStubMethodStubGenerator;
@@ -50,10 +51,11 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
return null;
}
- var path = GetInterceptorFilePath(context.Node.SyntaxTree, context.SemanticModel.Compilation);
- var lineSpan = context.SemanticModel.SyntaxTree.GetLineSpan(context.Node.Span);
- var line = lineSpan.StartLinePosition.Line + 1;
- var column = lineSpan.Span.Start.Character + context.Node.ToString().IndexOf("AddStub", StringComparison.Ordinal) + 1;
+ var interceptableLocation = context.SemanticModel.GetInterceptableLocation(invocation);
+ if (interceptableLocation is null)
+ {
+ return null;
+ }
var properties = symbol.GetAllMembersRecursively()
.OfType()
@@ -67,9 +69,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
TargetTypeNamespace = symbol.ContainingNamespace.ToDisplayString(),
TargetTypeName = symbol.ToDisplayString(),
Properties = properties,
- Path = path,
- Line = line,
- Column = column,
+ Location = interceptableLocation,
};
static bool IsComponentFactoryStubMethod(InvocationExpressionSyntax invocation, SemanticModel semanticModel)
@@ -88,11 +88,6 @@ static bool IsComponentFactoryStubMethod(InvocationExpressionSyntax invocation,
return semanticModel.GetSymbolInfo(invocation).Symbol is IMethodSymbol { IsExtensionMethod: true, ReceiverType.Name: "ComponentFactoryCollection" };
}
- static string GetInterceptorFilePath(SyntaxTree tree, Compilation compilation)
- {
- return compilation.Options.SourceReferenceResolver?.NormalizePath(tree.FilePath, baseFilePath: null) ?? tree.FilePath;
- }
-
static bool IsParameterOrCascadingParameter(ISymbol member)
{
return member.GetAttributes().Any(SupportedAttributes.IsSupportedAttribute);
@@ -124,27 +119,21 @@ private static void Execute(ImmutableArray classInfos, SourceP
private static void GenerateInterceptorCode(AddStubClassInfo stubbedComponentGroup, IEnumerable stubClassGrouped, SourceProductionContext context)
{
- // Generate the attribute
- const string attribute = """
- namespace System.Runtime.CompilerServices
- {
- [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
- sealed file class InterceptsLocationAttribute : Attribute
- {
- public InterceptsLocationAttribute(string filePath, int line, int column)
- {
- _ = filePath;
- _ = line;
- _ = column;
- }
- }
- }
- """;
-
// Generate the interceptor
var interceptorSource = new StringBuilder(1000);
interceptorSource.AppendLine(HeaderProvider.Header);
- interceptorSource.AppendLine(attribute);
+ interceptorSource.AppendLine("namespace System.Runtime.CompilerServices");
+ interceptorSource.AppendLine("{");
+ interceptorSource.AppendLine("\t[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = true)]");
+ interceptorSource.AppendLine("\tsealed file class InterceptsLocationAttribute : global::System.Attribute");
+ interceptorSource.AppendLine("\t{");
+ interceptorSource.AppendLine("\t\tpublic InterceptsLocationAttribute(int version, string data)");
+ interceptorSource.AppendLine("\t\t{");
+ interceptorSource.AppendLine("\t\t\t_ = version;");
+ interceptorSource.AppendLine("\t\t\t_ = data;");
+ interceptorSource.AppendLine("\t\t}");
+ interceptorSource.AppendLine("\t}");
+ interceptorSource.AppendLine("}");
interceptorSource.AppendLine();
interceptorSource.AppendLine("namespace Bunit");
interceptorSource.AppendLine("{");
@@ -153,8 +142,7 @@ public InterceptsLocationAttribute(string filePath, int line, int column)
foreach (var hit in stubClassGrouped)
{
- interceptorSource.AppendLine(
- $"\t\t[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(@\"{hit.Path}\", {hit.Line}, {hit.Column})]");
+ interceptorSource.AppendLine($"\t\t{hit.Location.GetInterceptsLocationAttributeSyntax()}");
}
interceptorSource.AppendLine(
@@ -213,9 +201,7 @@ internal sealed record AddStubClassInfo
public required string TargetTypeName { get; set; }
public string UniqueQualifier => $"{TargetTypeNamespace}.{StubClassName}";
public ImmutableArray Properties { get; set; } = ImmutableArray.Empty;
- public required string Path { get; set; }
- public int Line { get; set; }
- public int Column { get; set; }
+ public required InterceptableLocation Location { get; set; }
}
internal sealed record StubPropertyInfo