诊断位置和范围
本文档详细介绍如何精确指定诊断的位置和范围。
文档信息
- 难度级别: 中级
- 预计阅读时间: 15 分钟
🎯 学习目标
- ✅ 理解 Location 类的使用
- 学会使用 TextSpan 指定范围
- 掌握精确位置指定技巧
Location 类
Location 类表示源代码中的一个位置。
csharp
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
public class LocationExamples
{
public Location GetLocationFromNode(SyntaxNode node)
{
return node.GetLocation();
}
public Location GetLocationFromToken(SyntaxToken token)
{
return token.GetLocation();
}
public Location GetLocationFromSymbol(ISymbol symbol)
{
return symbol.Locations.FirstOrDefault();
}
public Location CreateCustomLocation(
SyntaxTree syntaxTree,
int start,
int length)
{
var span = new TextSpan(start, length);
return Location.Create(syntaxTree, span);
}
}TextSpan 使用
TextSpan 表示文本中的一个范围。
csharp
using Microsoft.CodeAnalysis.Text;
public class TextSpanExamples
{
public TextSpan CreateTextSpan(int start, int length)
{
return new TextSpan(start, length);
}
public TextSpan CreateTextSpanFromPositions(int start, int end)
{
return TextSpan.FromBounds(start, end);
}
public bool AreOverlapping(TextSpan span1, TextSpan span2)
{
return span1.OverlapsWith(span2);
}
}精确位置指定
csharp
public class PreciseLocationExamples
{
// 只标记方法名
public void ReportOnMethodName(
SyntaxNodeAnalysisContext context,
MethodDeclarationSyntax method)
{
var diagnostic = Diagnostic.Create(
Rule,
method.Identifier.GetLocation());
context.ReportDiagnostic(diagnostic);
}
// 标记方法签名(名称 + 参数列表)
public void ReportOnMethodSignature(
SyntaxNodeAnalysisContext context,
MethodDeclarationSyntax method)
{
var start = method.Identifier.SpanStart;
var end = method.ParameterList.Span.End;
var span = TextSpan.FromBounds(start, end);
var location = Location.Create(method.SyntaxTree, span);
var diagnostic = Diagnostic.Create(Rule, location);
context.ReportDiagnostic(diagnostic);
}
}相关文档
- 上一篇: DiagnosticAnalyzer 实现
- 下一篇: 消息格式化
- 返回: 诊断 API 索引
跨行诊断
处理跨越多行的诊断:
csharp
public class MultiLineDiagnosticExamples
{
private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(
id: "MULTI001",
title: "跨行问题",
messageFormat: "此代码块有问题",
category: "Demo",
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);
public void ReportOnCodeBlock(
SyntaxNodeAnalysisContext context,
BlockSyntax block)
{
var diagnostic = Diagnostic.Create(
Rule,
block.GetLocation());
context.ReportDiagnostic(diagnostic);
}
public void ReportOnBlockContent(
SyntaxNodeAnalysisContext context,
BlockSyntax block)
{
if (block.Statements.Count == 0)
return;
var start = block.Statements.First().SpanStart;
var end = block.Statements.Last().Span.End;
var span = TextSpan.FromBounds(start, end);
var location = Location.Create(block.SyntaxTree, span);
var diagnostic = Diagnostic.Create(Rule, location);
context.ReportDiagnostic(diagnostic);
}
public void ReportOnDisjointLocations(
SyntaxNodeAnalysisContext context,
params SyntaxNode[] nodes)
{
if (nodes.Length == 0)
return;
var mainLocation = nodes[0].GetLocation();
var additionalLocations = nodes.Skip(1)
.Select(n => n.GetLocation())
.ToImmutableArray();
var diagnostic = Diagnostic.Create(
Rule,
mainLocation,
additionalLocations,
null);
context.ReportDiagnostic(diagnostic);
}
}最佳实践
- 使用精确的位置 - 只标记有问题的部分
- 验证位置有效性 - 避免在元数据位置报告
- 使用 TextSpan 创建自定义范围 - 精确控制诊断范围
- 使用附加位置 - 显示相关代码
- 处理 partial 类 - 遍历所有位置
常见问题
Q: 如何只标记标识符而不是整个节点?
A: 使用 Token 的位置:
csharp
classDeclaration.Identifier.GetLocation()Q: 如何标记多个不连续的位置?
A: 使用附加位置:
csharp
var additionalLocations = ImmutableArray.Create(
location1, location2, location3);
var diagnostic = Diagnostic.Create(
Rule,
mainLocation,
additionalLocations,
null);Q: 如何检查位置是否在元数据中?
A: 使用 IsInMetadata 属性:
csharp
if (!location.IsInMetadata)
{
// 报告诊断
}