This project is used by Agoda internally for analysis of our C# projects. We have opened it for community contribution.
Take a look at the analyzer for our test method names which is fairly simple but not trivial.
An analyzer inherits from the abstract class DiagnosticAnalyzer
. It requires us to override two members:
A property specifying one or more DiagnosticDescriptor
s representing the metadata of your analyzer, for instance the title, error message, severity, etc.
Called by the hosting environment (eg. Visual Studio) to bootstrap your analyzer. In this method, we tell the Roslyn compiler:
- which
SyntaxKinds
we are interested in analyzing (eg.MethodDeclaration
,ClassDeclaration
,Parameter
) - for each of these
SyntaxKinds
, what method should be called to perform the actual analysis.
Here is an example:
public override void Initialize(AnalysisContext context)
{
// Each time the compiler encounters a method declaration, call the AnalyzeNode method.
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.MethodDeclaration);
}
This is where the fun begins. Each time the Roslyn compiler encounters a node with a registered SyntaxKind
it will call our AnalyzeNode
method with the context. For example:
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
// Upcast the node to the type that corresponds to the specific SyntaxKind we registered:
var methodDeclarationSyntax = (MethodDeclarationSyntax) context.Node;
// We can now do syntactic ("textual") analysis, such as checking if the method has a public modifier:
if (methodDeclarationSyntax.Modifiers.Any(SyntaxKind.PublicKeyword))
{
// ...
}
// We can also do semantic analysis, which gives us far deeper inspection opportunities than just
// looking at the syntax.
var methodDeclarationSymbol = context.SemanticModel.GetDeclaredSymbol(methodDeclarationSyntax);
// For example, we can check if it's an extension method:
if (methodDeclarationSymbol.IsExtensionMethod)
{
// ...
}
// Or we can get its attributes:
var methodAttributes = methodDeclarationSymbol.GetAttributes();
// Or anything else that the compiler can possibly know.
// If we find a problem, we report it like this. The Descriptor here refers to one of the descriptors
// we passed to the SupportedDiagnostics property above.
if (weFoundAnError)
{
context.ReportDiagnostic(Diagnostic.Create(Descriptor, methodDeclaration.GetLocation()));
}
}
In order to debug this project:
- Run the
Agoda.Analyzers.Vsix
as the start up project. It will open and attach to a second copy of VS2017. - Set a breakpoint in your analyzer in the first VS.
- Edit some code in the second VS that should cause your analyzer to fire. The breakpoint in the first VS should be hit and you can now step through.
Merged rules will be automatically added to our internal SonarQube instance. They must be activated manually, however.
To generate a jar file from this project for use with SonarQube we have prepared a fork of the Sonar team's project that has been updated to 1.3 here.