< Summary

Information
Class: NexusLabs.Needlr.Analyzers.RegisterAsAttributeAnalyzer
Assembly: NexusLabs.Needlr.Analyzers
File(s): /home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Analyzers/RegisterAsAttributeAnalyzer.cs
Line coverage
84%
Covered lines: 33
Uncovered lines: 6
Coverable lines: 39
Total lines: 98
Line coverage: 84.6%
Branch coverage
71%
Covered branches: 20
Total branches: 28
Branch coverage: 71.4%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_SupportedDiagnostics()100%11100%
Initialize(...)100%11100%
AnalyzeAttribute(...)75%212088%
IsRegisterAsAttribute(...)62.5%10866.66%

File(s)

/home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Analyzers/RegisterAsAttributeAnalyzer.cs

#LineLine coverage
 1using System.Collections.Immutable;
 2
 3using Microsoft.CodeAnalysis;
 4using Microsoft.CodeAnalysis.CSharp;
 5using Microsoft.CodeAnalysis.CSharp.Syntax;
 6using Microsoft.CodeAnalysis.Diagnostics;
 7
 8namespace NexusLabs.Needlr.Analyzers;
 9
 10/// <summary>
 11/// Analyzer that validates [RegisterAs&lt;T&gt;] attribute usage:
 12/// - NDLRCOR015: Type argument T is not an interface implemented by the class
 13/// </summary>
 14[DiagnosticAnalyzer(LanguageNames.CSharp)]
 15public sealed class RegisterAsAttributeAnalyzer : DiagnosticAnalyzer
 16{
 17    private const string RegisterAsAttributeName = "RegisterAsAttribute";
 18    private const string NeedlrNamespace = "NexusLabs.Needlr";
 19
 20    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
 16221        ImmutableArray.Create(DiagnosticDescriptors.RegisterAsTypeArgNotImplemented);
 22
 23    public override void Initialize(AnalysisContext context)
 24    {
 1525        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
 1526        context.EnableConcurrentExecution();
 27
 1528        context.RegisterSyntaxNodeAction(AnalyzeAttribute, SyntaxKind.Attribute);
 1529    }
 30
 31    private static void AnalyzeAttribute(SyntaxNodeAnalysisContext context)
 32    {
 8433        var attributeSyntax = (AttributeSyntax)context.Node;
 8434        var attributeSymbol = context.SemanticModel.GetSymbolInfo(attributeSyntax).Symbol?.ContainingType;
 35
 8436        if (attributeSymbol == null)
 037            return;
 38
 39        // Check if this is a [RegisterAs<T>] attribute
 8440        if (!IsRegisterAsAttribute(attributeSymbol))
 7241            return;
 42
 43        // Get the class this attribute is applied to
 1244        var classDeclaration = attributeSyntax.Parent?.Parent as ClassDeclarationSyntax;
 1245        if (classDeclaration == null)
 046            return;
 47
 1248        var classSymbol = context.SemanticModel.GetDeclaredSymbol(classDeclaration);
 1249        if (classSymbol == null)
 050            return;
 51
 52        // NDLRCOR015: Check if generic type argument is implemented by the class
 1253        if (attributeSymbol.IsGenericType && attributeSymbol.TypeArguments.Length == 1)
 54        {
 1255            var typeArg = attributeSymbol.TypeArguments[0] as INamedTypeSymbol;
 1256            if (typeArg != null)
 57            {
 58                // Check if the class implements this interface
 1259                bool implementsInterface = classSymbol.AllInterfaces.Any(i =>
 2860                    SymbolEqualityComparer.Default.Equals(i, typeArg));
 61
 1262                if (!implementsInterface)
 63                {
 664                    var diagnostic = Diagnostic.Create(
 665                        DiagnosticDescriptors.RegisterAsTypeArgNotImplemented,
 666                        attributeSyntax.GetLocation(),
 667                        classSymbol.Name,
 668                        typeArg.Name);
 69
 670                    context.ReportDiagnostic(diagnostic);
 71                }
 72            }
 73        }
 1274    }
 75
 76    private static bool IsRegisterAsAttribute(INamedTypeSymbol attributeSymbol)
 77    {
 78        // Handle RegisterAsAttribute<T>
 8479        var name = attributeSymbol.Name;
 8480        if (name != RegisterAsAttributeName)
 81        {
 82            // Check original definition for generic case
 7283            if (attributeSymbol.IsGenericType)
 84            {
 085                name = attributeSymbol.OriginalDefinition.Name;
 086                if (name != RegisterAsAttributeName)
 087                    return false;
 88            }
 89            else
 90            {
 7291                return false;
 92            }
 93        }
 94
 1295        var ns = attributeSymbol.ContainingNamespace?.ToString();
 1296        return ns == NeedlrNamespace;
 97    }
 98}