Deepstaging.Roslyn.Workspace
1.0.0-dev-20260205052640
dotnet add package Deepstaging.Roslyn.Workspace --version 1.0.0-dev-20260205052640
NuGet\Install-Package Deepstaging.Roslyn.Workspace -Version 1.0.0-dev-20260205052640
<PackageReference Include="Deepstaging.Roslyn.Workspace" Version="1.0.0-dev-20260205052640" />
<PackageVersion Include="Deepstaging.Roslyn.Workspace" Version="1.0.0-dev-20260205052640" />
<PackageReference Include="Deepstaging.Roslyn.Workspace" />
paket add Deepstaging.Roslyn.Workspace --version 1.0.0-dev-20260205052640
#r "nuget: Deepstaging.Roslyn.Workspace, 1.0.0-dev-20260205052640"
#:package Deepstaging.Roslyn.Workspace@1.0.0-dev-20260205052640
#addin nuget:?package=Deepstaging.Roslyn.Workspace&version=1.0.0-dev-20260205052640&prerelease
#tool nuget:?package=Deepstaging.Roslyn.Workspace&version=1.0.0-dev-20260205052640&prerelease
Deepstaging.Roslyn.Workspace
Code fix infrastructure for Roslyn analyzers using the Workspace API.
See also: Roslyn Toolkit | Testing
What is this?
This library provides base classes and utilities for building Roslyn code fix providers. It simplifies the boilerplate of registering code fixes and working with syntax nodes.
Quick Start
1. Define a code fix with attributes
[ExportCodeFixProvider(LanguageNames.CSharp)]
[CodeFix("MY001")]
[CodeFix("MY002")] // Can fix multiple diagnostics
public class AddPartialModifierCodeFix : SyntaxCodeFix<TypeDeclarationSyntax>
{
protected override CodeAction? CreateFix(Document document, ValidSyntax<TypeDeclarationSyntax> syntax)
{
return CodeAction.Create(
title: "Add partial modifier",
createChangedDocument: ct => AddPartialModifier(document, syntax.Node, ct),
equivalenceKey: "AddPartial");
}
private async Task<Document> AddPartialModifier(
Document document,
TypeDeclarationSyntax declaration,
CancellationToken ct)
{
var newDeclaration = declaration
.AddModifiers(SyntaxFactory.Token(SyntaxKind.PartialKeyword));
return await document.ReplaceNode(declaration, newDeclaration, ct);
}
}
2. That's it!
The base class handles:
- Reading
[CodeFix]attributes to populateFixableDiagnosticIds - Finding the syntax node at the diagnostic location
- Registering the code action with proper error handling
API Reference
SyntaxCodeFix<TSyntax>
Abstract base class for code fix providers:
public abstract class SyntaxCodeFix<TSyntax> : CodeFixProvider
where TSyntax : SyntaxNode
{
// Automatically populated from [CodeFix] attributes
public sealed override ImmutableArray<string> FixableDiagnosticIds { get; }
// Override to create your fix
protected abstract CodeAction? CreateFix(
Document document,
ValidSyntax<TSyntax> syntax);
}
CodeFixAttribute
Declarative configuration for code fixes:
[CodeFix("MY001")] // The diagnostic ID this code fix handles
[CodeFix("MY002")] // Add multiple attributes for multiple diagnostics
Specialized Base Classes
Pre-defined base classes for common syntax types:
// Type declarations
public abstract class ClassCodeFix : SyntaxCodeFix<ClassDeclarationSyntax>;
public abstract class StructCodeFix : SyntaxCodeFix<StructDeclarationSyntax>;
public abstract class InterfaceCodeFix : SyntaxCodeFix<InterfaceDeclarationSyntax>;
public abstract class RecordCodeFix : SyntaxCodeFix<RecordDeclarationSyntax>;
public abstract class EnumCodeFix : SyntaxCodeFix<EnumDeclarationSyntax>;
// Member declarations
public abstract class MethodCodeFix : SyntaxCodeFix<MethodDeclarationSyntax>;
public abstract class PropertyCodeFix : SyntaxCodeFix<PropertyDeclarationSyntax>;
public abstract class FieldCodeFix : SyntaxCodeFix<FieldDeclarationSyntax>;
public abstract class ConstructorCodeFix : SyntaxCodeFix<ConstructorDeclarationSyntax>;
public abstract class EventCodeFix : SyntaxCodeFix<EventDeclarationSyntax>;
public abstract class ParameterCodeFix : SyntaxCodeFix<ParameterSyntax>;
Document Extensions
Convenient methods for document manipulation:
// Replace a syntax node (async)
Document newDoc = await document.ReplaceNode(oldNode, newNode, cancellationToken);
// Replace a syntax node (sync, when root is already available)
Document newDoc = document.ReplaceNode(root, oldNode, newNode);
CodeFixContext Extensions
Helper methods for finding syntax nodes:
// Generic find
OptionalSyntax<TSyntax> result = await context.FindDeclaration<TypeDeclarationSyntax>();
// Type-specific helpers
OptionalSyntax<ClassDeclarationSyntax> classDecl = await context.FindClass();
OptionalSyntax<MethodDeclarationSyntax> methodDecl = await context.FindMethod();
OptionalSyntax<PropertyDeclarationSyntax> propDecl = await context.FindProperty();
// Also: FindStruct(), FindInterface(), FindRecord(), FindEnum(),
// FindField(), FindConstructor(), FindEvent(), FindParameter()
Projections
ValidSyntax<T>
A wrapper guaranteeing a non-null syntax node:
protected override CodeAction? CreateFix(Document document, ValidSyntax<TypeDeclarationSyntax> syntax)
{
// syntax.Node is guaranteed non-null
string name = syntax.Node.Identifier.Text;
// Access the underlying node
TypeDeclarationSyntax node = syntax.Node;
}
Why Use This?
Without this library:
public class MyCodeFix : CodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds =>
ImmutableArray.Create("MY001", "MY002");
public override FixAllProvider GetFixAllProvider() =>
WellKnownFixAllProviders.BatchFixer;
public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);
if (root == null) return;
var diagnostic = context.Diagnostics.First();
var node = root.FindNode(diagnostic.Location.SourceSpan);
if (node.FirstAncestorOrSelf<TypeDeclarationSyntax>() is not { } typeDecl)
return;
var codeAction = CodeAction.Create(...);
context.RegisterCodeFix(codeAction, diagnostic);
}
}
With this library:
[CodeFix("MY001")]
[CodeFix("MY002")]
public class MyCodeFix : SyntaxCodeFix<TypeDeclarationSyntax>
{
protected override CodeAction? CreateFix(Document document, ValidSyntax<TypeDeclarationSyntax> syntax)
{
return CodeAction.Create(...);
}
}
Related Documentation
- Roslyn Toolkit - Query builders, projections, and emit API
- Testing - Test infrastructure including code fix testing
- Main README - Project overview
License
RPL-1.5 (Reciprocal Public License) — Real reciprocity, no loopholes.
You can use this code, modify it, and share it freely. But when you deploy it — internally or externally, as a service or within your company — you share your improvements back under the same license.
Why? We believe if you benefit from this code, the community should benefit from your improvements. That's the deal we think is fair.
Personal research and experimentation? No obligations. Go learn, explore, and build.
See LICENSE for the full legal text.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Deepstaging.Roslyn (>= 1.0.0-dev-20260205052640)
- Microsoft.CodeAnalysis.Workspaces.Common (>= 5.0.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Deepstaging.Roslyn.Workspace:
| Package | Downloads |
|---|---|
|
Deepstaging.Roslyn.Testing
Testing infrastructure for Roslyn analyzers and generators. Includes TUnit base classes and Verify snapshot testing support. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0-dev-20260205052640 | 19 | 2/5/2026 |
| 1.0.0-dev-20260205050756 | 26 | 2/5/2026 |
| 1.0.0-dev-20260204225221 | 35 | 2/4/2026 |
| 1.0.0-dev-20260204225018 | 28 | 2/4/2026 |
| 1.0.0-dev-20260204223024 | 29 | 2/4/2026 |
| 1.0.0-dev-20260204222744 | 24 | 2/4/2026 |
| 1.0.0-dev-20260204221656 | 25 | 2/4/2026 |
| 1.0.0-dev-20260204221327 | 29 | 2/4/2026 |
| 1.0.0-dev-20260204221227 | 27 | 2/4/2026 |
| 1.0.0-dev-20260204221019 | 28 | 2/4/2026 |
| 1.0.0-dev-20260204220308 | 29 | 2/4/2026 |