Generator Infrastructure¶
Utility types for common incremental source generator tasks: cacheable diagnostics, partial type nesting, and embedded attribute registration.
See also: Generators Overview | PipelineModel | EquatableArray | EmitWriter
DiagnosticInfo¶
A pipeline-safe representation of a Diagnostic that does not root any syntax trees or symbols. Safe to store in [PipelineModel] models.
Why¶
Roslyn's Diagnostic holds a Location, which holds a SyntaxTree reference. Storing diagnostics in pipeline models defeats incremental caching. DiagnosticInfo extracts only primitive data, then reconstructs the Diagnostic in the output step.
Factory Methods¶
| Method | Description |
|---|---|
Create(DiagnosticDescriptor, Location, params string[]) |
Create from a descriptor and source location |
Create(DiagnosticDescriptor, params string[]) |
Create with no location |
Reconstruction¶
| Method | Description |
|---|---|
ToDiagnostic() |
Reconstruct a Diagnostic for reporting |
Example¶
// In the transform step — capture diagnostic data
var info = DiagnosticInfo.Create(
MyDiagnostics.MissingAttribute,
symbol.Locations[0],
symbol.Name);
// In the output step — reconstruct and report
context.ReportDiagnostic(info.ToDiagnostic());
Properties¶
| Property | Type | Description |
|---|---|---|
Descriptor |
DiagnosticDescriptor |
The diagnostic descriptor |
Location |
LocationInfo? |
The location info, or null |
MessageArgs |
EquatableArray<string> |
Format arguments |
LocationInfo¶
A pipeline-safe representation of a source code Location that does not root any syntax trees.
Factory Methods¶
| Method | Description |
|---|---|
From(Location) |
Create from a Roslyn Location. Returns null for non-source locations. |
Reconstruction¶
| Method | Description |
|---|---|
ToLocation() |
Reconstruct a Roslyn Location |
Properties¶
| Property | Type | Description |
|---|---|---|
FilePath |
string |
The source file path |
TextSpan |
TextSpan |
The text span within the file |
LineSpan |
LinePositionSpan |
The line/column span |
PartialTypeHierarchy¶
Reconstructs the namespace and parent type nesting for partial type declarations. Use this when a source generator emits code that extends a user-declared partial type.
Handles:
- File-scoped namespace declarations
- Arbitrary nesting depth (class inside struct inside class, etc.)
- Generic parent types with type parameters and constraints
- All type kinds: class, struct, record, record struct, interface
Methods¶
| Method | Description |
|---|---|
Write(EmitWriter, INamedTypeSymbol, Action<EmitWriter>) |
Write namespace + nesting, invoke callback for body content |
Write(EmitWriter, INamedTypeSymbol, string) |
Write namespace + nesting around a pre-built string body |
Example¶
using var writer = new EmitWriter();
writer.Comment("<auto-generated/>");
writer.NullableEnable();
writer.WriteLine();
PartialTypeHierarchy.Write(writer, targetTypeSymbol, inner =>
{
inner.WriteLine("public string GeneratedProperty => \"hello\";");
});
context.AddSource($"{typeName}.g.cs", writer.ToString());
For a type MyApp.Models.Outer.Inner, this produces:
// <auto-generated/>
#nullable enable
namespace MyApp.Models;
partial class Outer
{
partial class Inner
{
public string GeneratedProperty => "hello";
}
}
EmbeddedAttribute¶
Helper for registering embedded marker attributes in incremental source generators. Embedded attributes are compiled into the consumer's assembly with [Conditional("DEEPSTAGING_GENERATOR")] to prevent runtime dependency on the generator package.
Methods¶
| Method | Description |
|---|---|
Register(IncrementalGeneratorInitializationContext, EmbeddedAttributeOptions) |
Register an attribute via RegisterPostInitializationOutput |
BuildSource(EmbeddedAttributeOptions) |
Build the attribute source text without registering (useful for testing) |
EmbeddedAttributeOptions¶
| Property | Type | Default | Description |
|---|---|---|---|
Namespace |
string |
required | Namespace for the attribute |
Name |
string |
required | Attribute name (Attribute suffix added if missing) |
Targets |
AttributeTargets |
required | Valid attribute targets |
AllowMultiple |
bool |
false |
Allow multiple applications to the same target |
Properties |
IReadOnlyList<(string Type, string Name)>? |
null |
Optional auto-properties on the attribute |
Example¶
public void Initialize(IncrementalGeneratorInitializationContext context)
{
EmbeddedAttribute.Register(context, new EmbeddedAttributeOptions
{
Namespace = "MyGenerator",
Name = "AutoNotify",
Targets = AttributeTargets.Field,
Properties = [("string?", "PropertyName")]
});
// Generator pipeline uses the registered attribute...
}
This generates an internal sealed class AutoNotifyAttribute with [Conditional] and [AttributeUsage] decorations, plus a PropertyName auto-property.