< Summary

Information
Class: NexusLabs.Needlr.AgentFramework.Analyzers.AgentGroupChatSingletonAnalyzer
Assembly: NexusLabs.Needlr.AgentFramework.Analyzers
File(s): /home/runner/work/needlr/needlr/src/NexusLabs.Needlr.AgentFramework.Analyzers/AgentGroupChatSingletonAnalyzer.cs
Line coverage
100%
Covered lines: 55
Uncovered lines: 0
Coverable lines: 55
Total lines: 81
Line coverage: 100%
Branch coverage
85%
Covered branches: 17
Total branches: 20
Branch coverage: 85%
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(...)85%2020100%

File(s)

/home/runner/work/needlr/needlr/src/NexusLabs.Needlr.AgentFramework.Analyzers/AgentGroupChatSingletonAnalyzer.cs

#LineLine coverage
 1using System.Collections.Concurrent;
 2using System.Collections.Immutable;
 3
 4using Microsoft.CodeAnalysis;
 5using Microsoft.CodeAnalysis.Diagnostics;
 6
 7namespace NexusLabs.Needlr.AgentFramework.Analyzers;
 8
 9/// <summary>
 10/// Analyzer that validates <c>[AgentGroupChatMember]</c> group declarations.
 11/// </summary>
 12/// <remarks>
 13/// <b>NDLRMAF002</b> (Error): A named group chat has fewer than two members in this compilation.
 14/// <c>IWorkflowFactory.CreateGroupChatWorkflow</c> throws at runtime when this condition is met.
 15/// </remarks>
 16[DiagnosticAnalyzer(LanguageNames.CSharp)]
 17public sealed class AgentGroupChatSingletonAnalyzer : DiagnosticAnalyzer
 18{
 19    private const string AgentGroupChatMemberAttributeName = "NexusLabs.Needlr.AgentFramework.AgentGroupChatMemberAttrib
 20
 21    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
 8922        ImmutableArray.Create(MafDiagnosticDescriptors.GroupChatTooFewMembers);
 23
 24    public override void Initialize(AnalysisContext context)
 25    {
 1226        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
 1227        context.EnableConcurrentExecution();
 28
 1229        context.RegisterCompilationStartAction(compilationContext =>
 1230        {
 1231            // group name → list of (type symbol, attribute location)
 732            var groupMembers = new ConcurrentDictionary<string, ConcurrentBag<(INamedTypeSymbol Type, Location Location)
 733                StringComparer.Ordinal);
 1234
 735            compilationContext.RegisterSymbolAction(symbolContext =>
 736            {
 7737                var typeSymbol = (INamedTypeSymbol)symbolContext.Symbol;
 738
 32039                foreach (var attr in typeSymbol.GetAttributes())
 740                {
 8341                    if (attr.AttributeClass?.ToDisplayString() != AgentGroupChatMemberAttributeName)
 742                        continue;
 743
 1344                    if (attr.ConstructorArguments.Length < 1)
 745                        continue;
 746
 1347                    var groupName = attr.ConstructorArguments[0].Value as string;
 1348                    if (string.IsNullOrWhiteSpace(groupName))
 749                        continue;
 750
 1351                    var attrLocation = attr.ApplicationSyntaxReference?.SyntaxTree is { } tree
 1352                        ? Location.Create(tree, attr.ApplicationSyntaxReference.Span)
 1353                        : typeSymbol.Locations[0];
 754
 2155                    groupMembers.GetOrAdd(groupName!, _ => new ConcurrentBag<(INamedTypeSymbol, Location)>())
 1356                        .Add((typeSymbol, attrLocation));
 757                }
 8458            }, SymbolKind.NamedType);
 1259
 760            compilationContext.RegisterCompilationEndAction(endContext =>
 761            {
 3062                foreach (var kvp in groupMembers)
 763                {
 864                    var members = kvp.Value.ToList();
 865                    if (members.Count >= 2)
 766                        continue;
 767
 768                    // Report on every contributing class so the squiggle appears where the attribute is
 1669                    foreach (var (_, location) in members)
 770                    {
 471                        endContext.ReportDiagnostic(Diagnostic.Create(
 472                            MafDiagnosticDescriptors.GroupChatTooFewMembers,
 473                            location,
 474                            kvp.Key,
 475                            members.Count));
 776                    }
 777                }
 1478            });
 1979        });
 1280    }
 81}