< Summary

Information
Class: NexusLabs.Needlr.AgentFramework.Analyzers.AgentFunctionTypesMiswiredAnalyzer
Assembly: NexusLabs.Needlr.AgentFramework.Analyzers
File(s): /home/runner/work/needlr/needlr/src/NexusLabs.Needlr.AgentFramework.Analyzers/AgentFunctionTypesMiswiredAnalyzer.cs
Line coverage
100%
Covered lines: 30
Uncovered lines: 0
Coverable lines: 30
Total lines: 81
Line coverage: 100%
Branch coverage
83%
Covered branches: 20
Total branches: 24
Branch coverage: 83.3%
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%
AnalyzeNamedType(...)86.36%2222100%
HasAnyAgentFunctionMethod(...)50%22100%

File(s)

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

#LineLine coverage
 1using System.Collections.Immutable;
 2
 3using Microsoft.CodeAnalysis;
 4using Microsoft.CodeAnalysis.Diagnostics;
 5
 6namespace NexusLabs.Needlr.AgentFramework.Analyzers;
 7
 8/// <summary>
 9/// Analyzer that detects types listed in <c>FunctionTypes</c> on <c>[NeedlrAiAgent]</c> that
 10/// have no <c>[AgentFunction]</c> methods, causing the agent to silently receive zero tools.
 11/// </summary>
 12/// <remarks>
 13/// <b>NDLRMAF014</b> (Warning): A type in <c>FunctionTypes</c> has no <c>[AgentFunction]</c> methods.
 14/// </remarks>
 15[DiagnosticAnalyzer(LanguageNames.CSharp)]
 16public sealed class AgentFunctionTypesMiswiredAnalyzer : DiagnosticAnalyzer
 17{
 18    private const string NeedlrAiAgentAttributeName = "NexusLabs.Needlr.AgentFramework.NeedlrAiAgentAttribute";
 19    private const string AgentFunctionAttributeName = "NexusLabs.Needlr.AgentFramework.AgentFunctionAttribute";
 20
 21    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
 15522        ImmutableArray.Create(MafDiagnosticDescriptors.AgentFunctionTypesMiswired);
 23
 24    public override void Initialize(AnalysisContext context)
 25    {
 1526        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
 1527        context.EnableConcurrentExecution();
 1528        context.RegisterSymbolAction(AnalyzeNamedType, SymbolKind.NamedType);
 1529    }
 30
 31    private static void AnalyzeNamedType(SymbolAnalysisContext context)
 32    {
 10333        var typeSymbol = (INamedTypeSymbol)context.Symbol;
 34
 37235        foreach (var attr in typeSymbol.GetAttributes())
 36        {
 8337            if (attr.AttributeClass?.ToDisplayString() != NeedlrAiAgentAttributeName)
 38                continue;
 39
 1140            var functionTypesArg = attr.NamedArguments
 2141                .FirstOrDefault(n => n.Key == "FunctionTypes");
 42
 1143            if (functionTypesArg.Key is null)
 44                continue;
 45
 1046            if (functionTypesArg.Value.Kind != TypedConstantKind.Array)
 47                continue;
 48
 4249            foreach (var element in functionTypesArg.Value.Values)
 50            {
 1151                if (element.Kind != TypedConstantKind.Type)
 52                    continue;
 53
 1154                if (element.Value is not INamedTypeSymbol functionType)
 55                    continue;
 56
 1157                var hasAgentFunction = HasAnyAgentFunctionMethod(functionType);
 1158                if (hasAgentFunction)
 59                    continue;
 60
 861                var location = attr.ApplicationSyntaxReference?.SyntaxTree is { } tree
 862                    ? Location.Create(tree, attr.ApplicationSyntaxReference.Span)
 863                    : typeSymbol.Locations[0];
 64
 865                context.ReportDiagnostic(Diagnostic.Create(
 866                    MafDiagnosticDescriptors.AgentFunctionTypesMiswired,
 867                    location,
 868                    functionType.Name,
 869                    typeSymbol.Name));
 70            }
 71        }
 10372    }
 73
 74    private static bool HasAnyAgentFunctionMethod(INamedTypeSymbol type)
 75    {
 1176        return type.GetMembers()
 1177            .OfType<IMethodSymbol>()
 2678            .Any(m => m.GetAttributes()
 2979                .Any(a => a.AttributeClass?.ToDisplayString() == AgentFunctionAttributeName));
 80    }
 81}