Creating a custom metric
Step 1. Reference the Metalama SDK
Start by referencing Metalama.Framework.Sdk
and Metalama.Framework
, both privately:
<PackageReference Include="Metalama.Framework.Sdk" Version="$(MetalamaVersion)" PrivateAssets="all" />
<PackageReference Include="Metalama.Framework" Version="$(MetalamaVersion)" PrivateAssets="all" />
Step 2. Create the metric public API
Create a struct
that implements the IMetric<T> generic interface. The type parameter should be the type of declaration to which the metric applies (e.g., IMethod
or IField
). Note that your metric struct
can implement several generic instances of the IMetric<T> interface simultaneously.
Typically, your metric struct
will have at least one public property. It will also have internal members to update the values, which will be utilized by the metric implementation.
Example
The following example demonstrates a single-value metric.
public struct SyntaxNodesCount : IMetric<IMethodBase>, IMetric<INamedType>, IMetric<INamespace>, IMetric<ICompilation>
{
public int Value { get; internal set; }
internal void Add( in SyntaxNodesCount other ) => this.Value += other.Value;
}
Step 3. Create the metric implementation
A metric requires several implementation classes:
Create a public class that derives from SyntaxMetricProvider<T>, where
T
is the metric type created above. In the constructor, pass an instance of the visitor created in the next step.Inside the metric provider class, create a nested visitor class that derives from SyntaxMetricProvider<T>.BaseVisitor. Override the relevant
Visit
methods in this class. This class forms the actual implementation of the metric. The visitor should recursively compute the metric for each syntax node in the syntax tree. The visitor is invoked by the metric provider (described below) for each member. The visitor should not implement aggregation at the type or namespace level.Implement the Aggregate method. This method is used to aggregate the metric from the level of members to the level of types, namespaces, or the whole project.
Annotate this class with the MetalamaPlugInAttribute custom attribute.
Example: counting syntax nodes
The following example implements a metric that counts the number of nodes in a member.
[MetalamaPlugIn]
public class SyntaxNodesCountMetricProvider : SyntaxMetricProvider<SyntaxNodesCount>
{
public SyntaxNodesCountMetricProvider() : base( new Visitor() ) { }
protected override void Aggregate( ref SyntaxNodesCount aggregate, in SyntaxNodesCount newValue )
=> aggregate.Add( newValue );
private class Visitor : BaseVisitor
{
public override SyntaxNodesCount DefaultVisit( SyntaxNode node )
{
var metric = new SyntaxNodesCount { Value = 1 };
foreach ( var child in node.ChildNodes() )
{
metric.Add( this.Visit( child ) );
}
return metric;
}
}
}
Consuming a custom metric
Custom metrics can be consumed in the usual manner.