Roslyn analyzers help to write high quality code in .NET using the Roslyn API and C#. The are like an eslinter in the node.js world.
First of all. This is an analyzer, not a code-fix.
1) Lets create a CancellationTokenAnalyzer.csproj with the following content. (netstandard2.0 is required. We can still use some new C# features by specifying the language version)
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>preview</LangVersion>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
👇 Required for debugging in Visual Studio
<IsRoslynComponent>true</IsRoslynComponent>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" />
</ItemGroup>
</Project>
2) Create a file called CancellationTokenArgumentAnalyzer.cs
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class CancellationTokenArgumentAnalyzer : DiagnosticAnalyzer
{
private static readonly DiagnosticDescriptor _rule = new(
id: "CancellationTokenArgumentAnalyzer",
title: "Checks missing CancellationToken argument",
messageFormat: "Missing CancellationToken argument for '{0}'",
category: "CancellationToken",
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true,
description: "Checks missing CancellationToken argument.");
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(_rule);
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterOperationAction(AnalyzeOperation, OperationKind.Invocation);
}
private static void AnalyzeOperation(OperationAnalysisContext context)
{
if (context.Operation is not IInvocationOperation invocationOperation)
{
return;
}
var methodSymbol = invocationOperation.TargetMethod;
var arguments = invocationOperation.Arguments;
if (methodSymbol.ReturnType.Name is not "Task" or "ValueTask")
{
return;
}
if (!arguments.Any(x => x.Value.Type?.Name == "CancellationToken"))
{
var diagnostic = Diagnostic.Create(_rule, invocationOperation.Syntax.GetLocation(), methodSymbol.Name);
context.ReportDiagnostic(diagnostic);
}
}
}
3) Add the following line to the consuming MyApplication.csproj.
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
👇
<PackageReference Include="..\CancellationTokenAnalyzer\CancellationTokenAnalyzer.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
</Project>
4) Compile the consuming MyApplication.csproj
dotnet build
Done! You should now see all warnings about missing CancellationToken's. 😊
Visual Studio (not VS Code) will run analyzers automatically while coding. Unfortunately performance is a huge issue. So we should write analyzers as efficient as possible.