Adjust analyzer diagnostic severities and improve MCP001 reporting (#1038)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
This commit is contained in:
Copilot 2025-11-26 21:51:37 -05:00 • committed by GitHub
commit b230b17ec9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 17 additions and 14 deletions

View file

@ -25,7 +25,7 @@ internal static class Diagnostics
title: "MCP method must be partial to generate [Description] attributes", title: "MCP method must be partial to generate [Description] attributes",
messageFormat: "Method '{0}' has XML documentation that could be used to generate [Description] attributes, but the method is not declared as partial.", messageFormat: "Method '{0}' has XML documentation that could be used to generate [Description] attributes, but the method is not declared as partial.",
category: "mcp", category: "mcp",
defaultSeverity: DiagnosticSeverity.Warning, defaultSeverity: DiagnosticSeverity.Info,
isEnabledByDefault: true, isEnabledByDefault: true,
description: "Methods with MCP attributes should be declared as partial to allow the source generator to emit Description attributes from XML documentation comments."); description: "Methods with MCP attributes should be declared as partial to allow the source generator to emit Description attributes from XML documentation comments.");
} }

View file

@ -72,7 +72,7 @@ public sealed class XmlToDescriptionGenerator : IIncrementalGenerator
List<(IMethodSymbol MethodSymbol, MethodDeclarationSyntax MethodDeclaration, XmlDocumentation? XmlDocs)> methodsToGenerate = new(methods.Length); List<(IMethodSymbol MethodSymbol, MethodDeclarationSyntax MethodDeclaration, XmlDocumentation? XmlDocs)> methodsToGenerate = new(methods.Length);
foreach (var methodModel in methods) foreach (var methodModel in methods)
{ {
var xmlDocs = ExtractXmlDocumentation(methodModel.MethodSymbol, context); var xmlDocs = ExtractXmlDocumentation(methodModel.MethodSymbol, methodModel.MethodDeclaration, context);
// Generate implementation for partial methods. // Generate implementation for partial methods.
if (methodModel.MethodDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword)) if (methodModel.MethodDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword))
@ -97,7 +97,7 @@ public sealed class XmlToDescriptionGenerator : IIncrementalGenerator
} }
} }
private static XmlDocumentation? ExtractXmlDocumentation(IMethodSymbol methodSymbol, SourceProductionContext context) private static XmlDocumentation? ExtractXmlDocumentation(IMethodSymbol methodSymbol, MethodDeclarationSyntax methodDeclaration, SourceProductionContext context)
{ {
string? xmlDoc = methodSymbol.GetDocumentationCommentXml(); string? xmlDoc = methodSymbol.GetDocumentationCommentXml();
if (string.IsNullOrWhiteSpace(xmlDoc)) if (string.IsNullOrWhiteSpace(xmlDoc))
@ -138,11 +138,14 @@ public sealed class XmlToDescriptionGenerator : IIncrementalGenerator
} }
catch (System.Xml.XmlException) catch (System.Xml.XmlException)
{ {
// Emit warning for invalid XML // Emit warning for invalid XML only if the method is partial (as that's when it would affect generated code)
context.ReportDiagnostic(Diagnostic.Create( if (methodDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword))
Diagnostics.InvalidXmlDocumentation, {
methodSymbol.Locations.FirstOrDefault(), context.ReportDiagnostic(Diagnostic.Create(
methodSymbol.Name)); Diagnostics.InvalidXmlDocumentation,
methodSymbol.Locations.FirstOrDefault(),
methodSymbol.Name));
}
return null; return null;
} }
} }

View file

@ -381,7 +381,7 @@ public partial class XmlToDescriptionGeneratorTests
// Should report MCP002 diagnostic // Should report MCP002 diagnostic
var diagnostic = Assert.Single(result.Diagnostics, d => d.Id == "MCP002"); var diagnostic = Assert.Single(result.Diagnostics, d => d.Id == "MCP002");
Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity); Assert.Equal(DiagnosticSeverity.Info, diagnostic.Severity);
Assert.Contains("TestMethod", diagnostic.GetMessage()); Assert.Contains("TestMethod", diagnostic.GetMessage());
Assert.Contains("partial", diagnostic.GetMessage()); Assert.Contains("partial", diagnostic.GetMessage());
} }
@ -412,7 +412,7 @@ public partial class XmlToDescriptionGeneratorTests
// Should report MCP002 diagnostic because parameter has documentation // Should report MCP002 diagnostic because parameter has documentation
var diagnostic = Assert.Single(result.Diagnostics, d => d.Id == "MCP002"); var diagnostic = Assert.Single(result.Diagnostics, d => d.Id == "MCP002");
Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity); Assert.Equal(DiagnosticSeverity.Info, diagnostic.Severity);
} }
[Fact] [Fact]
@ -441,7 +441,7 @@ public partial class XmlToDescriptionGeneratorTests
// Should report MCP002 diagnostic because return has documentation // Should report MCP002 diagnostic because return has documentation
var diagnostic = Assert.Single(result.Diagnostics, d => d.Id == "MCP002"); var diagnostic = Assert.Single(result.Diagnostics, d => d.Id == "MCP002");
Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity); Assert.Equal(DiagnosticSeverity.Info, diagnostic.Severity);
} }
[Fact] [Fact]
@ -559,7 +559,7 @@ public partial class XmlToDescriptionGeneratorTests
// Should report MCP002 diagnostic because parameter description would be generated // Should report MCP002 diagnostic because parameter description would be generated
var diagnostic = Assert.Single(result.Diagnostics, d => d.Id == "MCP002"); var diagnostic = Assert.Single(result.Diagnostics, d => d.Id == "MCP002");
Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity); Assert.Equal(DiagnosticSeverity.Info, diagnostic.Severity);
} }
[Fact] [Fact]
@ -590,7 +590,7 @@ public partial class XmlToDescriptionGeneratorTests
// Should report MCP002 diagnostic for prompts too // Should report MCP002 diagnostic for prompts too
var diagnostic = Assert.Single(result.Diagnostics, d => d.Id == "MCP002"); var diagnostic = Assert.Single(result.Diagnostics, d => d.Id == "MCP002");
Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity); Assert.Equal(DiagnosticSeverity.Info, diagnostic.Severity);
} }
[Fact] [Fact]
@ -621,7 +621,7 @@ public partial class XmlToDescriptionGeneratorTests
// Should report MCP002 diagnostic for resources too // Should report MCP002 diagnostic for resources too
var diagnostic = Assert.Single(result.Diagnostics, d => d.Id == "MCP002"); var diagnostic = Assert.Single(result.Diagnostics, d => d.Id == "MCP002");
Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity); Assert.Equal(DiagnosticSeverity.Info, diagnostic.Severity);
} }
[Fact] [Fact]