You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Roslyn分析器的NoPropertiesInitialized_Diagnostic测试运行失败?

问题根因

  • 诊断位置选择错误:你当前上报诊断时使用了整个LocalDeclarationStatementSyntax节点的位置,该节点包含了语句末尾的分号,导致实际结束列比预期多1位(从38变成39),和测试预期的Span范围不匹配。
  • 节点匹配逻辑可优化:你当前通过GetTypeByMetadataName拿类型符号的方式存在同名称不同命名空间类匹配错误的风险,且没有提前判空ObjectCreationExpressionSyntax,极端情况下会触发空引用异常。

修复方案

第一步:调整诊断上报逻辑

修改AnalyzeNode方法,提取目标ObjectCreationExpressionSyntax节点的位置进行上报,替换原来使用整个本地声明节点位置的逻辑,同时优化判空和类型匹配逻辑:

public override void Initialize(AnalysisContext context)
{
    context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
    context.EnableConcurrentExecution();
    context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.LocalDeclarationStatement);
}

private static void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
    var localDeclaration = (LocalDeclarationStatementSyntax)context.Node;
    var typeDeclaration = localDeclaration.Declaration.Type;
    var symbolInfo = context.SemanticModel.GetSymbolInfo(typeDeclaration);
    var typeSymbol = symbolInfo.Symbol;
    
    if(typeSymbol == null)
        return;

    // 过滤var别名场景
    var aliasInfo = context.SemanticModel.GetAliasInfo(typeDeclaration);
    if (aliasInfo != null)
        return;

    // 优化类型符号获取逻辑,避免同名称类匹配错误
    if (typeSymbol is not INamedTypeSymbol namedSymbol || namedSymbol.TypeKind != TypeKind.Class)
        return;

    // 校验无参构造函数存在
    var hasDefaultConstructor = namedSymbol.Constructors.Any(c => !c.Parameters.Any());
    if (!hasDefaultConstructor)
        return;

    // 筛选可初始化的公共属性
    var properties = namedSymbol.GetMembers()
        .Where(m => m.Kind == SymbolKind.Property
                    && m.DeclaredAccessibility == Accessibility.Public
                    && !((IPropertySymbol)m).IsReadOnly
                    && !((IPropertySymbol)m).IsStatic)
        .Select(m => new
        {
            Name = m.Name,
            Type = ((IPropertySymbol)m).Type
        })
        .ToList();
    if (!properties.Any())
        return;

    // 提前判空对象创建表达式和初始器
    var variable = localDeclaration.Declaration.Variables.FirstOrDefault();
    if (variable?.Initializer?.Value is not ObjectCreationExpressionSyntax objectCreation || objectCreation.Initializer == null)
        return;

    // 校验是否存在未初始化的属性
    var initializerExpressions = objectCreation.Initializer.Expressions.ToList();
    var uninitializedProperties = properties.Select(p => p.Name)
        .Except(initializerExpressions.Select(e => (e as AssignmentExpressionSyntax)?.Left.ToString()))
        .ToList();
    
    if(uninitializedProperties.Count == 0)
        return;

    // 改用对象创建表达式的位置上报,不包含末尾分号,范围匹配测试预期
    context.ReportDiagnostic(Diagnostic.Create(Rule, objectCreation.GetLocation()));
}

第二步:可选调整测试预期

如果你希望诊断范围覆盖整个var myClass = new MyClass { }语句(不含分号),可以手动裁剪LocalDeclaration的位置,替换上报逻辑即可:

var fullLocation = localDeclaration.GetLocation();
var adjustedSpan = TextSpan.FromBounds(fullLocation.SourceSpan.Start, fullLocation.SourceSpan.End - 1);
var adjustedLocation = Location.Create(fullLocation.SourceTree, adjustedSpan);
context.ReportDiagnostic(Diagnostic.Create(Rule, adjustedLocation));

修改完成后重新运行测试即可通过。

内容的提问来源于stack exchange,提问作者ʃʈɑɲ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 22:39:01