Search code examples
c#roslyn-code-analysis

C# Analyzers: How to enforce XML doc on interface members (and not everything else)?


I would like to enforce the usage of XML documentation on interface members in C# projects.

I'm looking for the same kind of behavior as SA1600 or CS1591 but limited to interfaces instead of all types.

How can I achieve this?


Solution

  • You can keep SA1600 nor CS1591 and suppress the warnings you don't want with a custom DiagnosticSuppressor similar to this :

    [DiagnosticAnalyzer(LanguageNames.CSharp)]
    internal sealed class MyDiagnosticSuppressor : DiagnosticSuppressor
    {
        private static readonly SuppressionDescriptor Rule = new SuppressionDescriptor("SUPCS1591", "CS1591", "Justification");
    
        public override ImmutableArray<SuppressionDescriptor> SupportedSuppressions => ImmutableArray.Create(Rule);
    
        public override void ReportSuppressions(SuppressionAnalysisContext context)
        {
            foreach (var diagnostic in context.ReportedDiagnostics)
            {
                if (!context.CancellationToken.IsCancellationRequested)
                {
                    Location location = diagnostic.Location;
                    SyntaxNode node = location.SourceTree.GetRoot(context.CancellationToken).FindNode(location.SourceSpan);
                    if (!(node is InterfaceDeclarationSyntax || HasParentOfType<InterfaceDeclarationSyntax>(node)))
                    {
                        context.ReportSuppression(Suppression.Create(Rule, diagnostic));
                    }
                }
            }
        }
    
        public bool HasParentOfType<TSearched>(SyntaxNode syntaxNode) where TSearched : SyntaxNode
        {
            return syntaxNode != null && (syntaxNode.Parent is TSearched || HasParentOfType<TSearched>(syntaxNode.Parent));
        }
    }
    

    A few things that you could want to customize based on your question :

    • The rule you're targetting, here we're targetting CS1591 (the second constructor parameter for our SuppressionDescriptor)
    • When to suppress the warning, here we're suppressing it whenever we're not on an interface declaration (node is InterfaceDeclarationSyntax) or within an interface declaration (HasParentOfType<InterfaceDeclarationSyntax>(node))

    Note that the current code probably won't behave like you wish in a few edge cases like classes declared within an interface declaration but I think it's a pretty solid basis to start with.