Writing and Distributing Roslyn Analyzers with MyGet
Join the DZone community and get the full member experience.
Join For FreePretty sweet: MyGet just announced Vsix support has been enabled for all MyGet customers! I wanted to work on a fun example for this new feature and came up with this: how can we use MyGet to build and distribute a Roslyn analyzer and code fix? Let’s see.
Developing a Roslyn analyzer and code fix
Roslyn analyzers and code fixes allow development teams and individuals to enforce certain rules within a code base. Using code fixes, it’s also possible to provide automated “fixes” for issues found in code. When writing code that utilizes DateTime, it’s often best to use DateTime.UtcNow instead of DateTime.Now. The first uses UTC timezone, while the latter uses the local time zone of the computer the code runs on, often introducing nasty time-related bugs. Let’s write an analyzer that detects usage of DateTime.Now!
You will need Visual Studio 2015 RC and the Visual Studio 2015 RC SDK installed. You’ll also need the SDK Templates VSIX package to get the Visual Studio project templates. Once you have those, we can create a new Analyzer with Code Fix.
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeIdentifierName, SyntaxKind.IdentifierName);
}
private void AnalyzeIdentifierName(SyntaxNodeAnalysisContext context)
{
var identifierName = context.Node as IdentifierNameSyntax;
if (identifierName != null)
{
// Find usages of "DateTime.Now"
if (identifierName.Identifier.ValueText == "Now"
&& ((IdentifierNameSyntax)((MemberAccessExpressionSyntax)identifierName.Parent).Expression).Identifier.ValueText == "DateTime")
{
// Produce a diagnostic.
var diagnostic = Diagnostic.Create(Rule, identifierName.Identifier.GetLocation(), identifierName);
context.ReportDiagnostic(diagnostic);
}
}
}
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
var diagnostic = context.Diagnostics.First();
var diagnosticSpan = diagnostic.Location.SourceSpan;
// Find "Now"
var identifierNode = root.FindNode(diagnosticSpan);
// Register a code action that will invoke the fix.
context.RegisterCodeFix(
CodeAction.Create("Replace with DateTime.UtcNow", c => ReplaceWithDateTimeUtcNow(context.Document, identifierNode, c)),
diagnostic);
}
private async Task<Document> ReplaceWithDateTimeUtcNow(Document document, SyntaxNode identifierNode, CancellationToken cancellationToken)
{
var root = await document.GetSyntaxRootAsync(cancellationToken);
var newRoot = root.ReplaceNode(identifierNode, SyntaxFactory.IdentifierName("UtcNow"));
return document.WithSyntaxRoot(newRoot);
}
Now let’s distribute it to our team!
Distributing a Roslyn analyzer and code fix using MyGet
Roslyn analyzers can be distributed in two formats: as NuGet packages, so they can be enabled for individual project, and as a Visual Studio extension so that all projects we work with have the analyzer and code fix enabled. You can build on a developer machine, a CI server or using MyGet Build Services. Let’s pick the latter as it’s the easiest way to achieve our goal: compile and distribute.
Create a new feed on www.myget.org. Next, from the Build Services tab, we can add a GitHub repository as the source. We’ve open-sourced our example at https://github.com/myget/sample-roslyn-with-vsix so feel free to add it to your feed as a test. Once added, you can start a build. Just like that. MyGet will figure out it’s a Roslyn analyzer and build both the NuGet package as well as the Visual Studio extension.
Sweet! You can now add the Roslyn analyzer and code fix per-project, by installing the NuGet package from the feed (https://www.myget.org/F/datetime-analyzer/api/v2). ANd when registering it in Visual Studio (https://www.myget.org/F/datetime-analyzer/vsix/) by opening the Tools | Options... menu and the Environment | Extensions and Updates pane, you can also install the full extension.
Published at DZone with permission of Maarten Balliauw, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments