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

调用DataFlowAnalysis导致Roslyn分析器停止运行问题排查

关于Roslyn分析器DataFlowAnalysis使用问题的排查与解决

问题背景

我正在开发一款Roslyn分析器,需求如下:

  • 查找所有静态字段声明
  • 若存在静态字段,检查是否有标注RuntimeInitializeOnLoadMethod特性的函数,若无则触发诊断
  • 若存在该函数,检查静态字段是否在该方法范围内被赋值,未赋值则触发诊断

步骤1和2运行正常,但步骤3出现问题。我的实现思路是:获取标注RuntimeInitializeOnLoadMethod特性的函数的SyntaxNode,对其执行DataFlowAnalysis,再检查静态字段的符号是否在DataFlowAnalysis.AlwaysAssigned中。但调用DataFlowAnalysis后,分析器似乎不再继续执行。

相关实现代码

private static void AnalyzeStaticFields(SyntaxNodeAnalysisContext context)
{
    var declaration = (FieldDeclarationSyntax)context.Node;

    if (declaration.Modifiers.Any(SyntaxKind.StaticKeyword))
    {
        // Find node with RuntimeInitializeOnLoadMethodAttribute
        SyntaxNode initializationNode;
        
        if (GetInitializationNode(context, out initializationNode)) {

            DataFlowAnalysis dataFlowAnalysis = context.SemanticModel.AnalyzeDataFlow(initializationNode);
            foreach (var variable in declaration.Declaration.Variables)
            {
                //Get symbol of static variable
               ISymbol variableSymbol = context.SemanticModel.GetDeclaredSymbol(variable, context.CancellationToken);

                //Check if static variable is assigned within scope of function
                if (dataFlowAnalysis.AlwaysAssigned.Contains(variableSymbol))
                {
                    var diagnostic = Diagnostic.Create(FieldRule, context.Node.GetLocation(), declaration.Declaration.Variables.First().Identifier.ValueText);

                    context.ReportDiagnostic(diagnostic);
                }
            }
        }
    }
}

测试代码

期望Class2中的intContent变量触发诊断,但实际并未触发。若移除AnalyzeDataFlow调用并注释相关条件,诊断信息会正常显示:

class Class2
{
    private static string stringContent = "This is the default value";
    private static int intContent = -1;

    [RuntimeInitializeOnLoadMethod]
    static void OnEnterPlayMode() {
        stringContent = "Initialised value";
    }

    public static void Test()
    {
        Debug.Log($"{stringContent} {intContent}");
        EventExample.StaticEvent += Test;
    }
}

问题分析与修正方案

核心问题点

  1. 判断逻辑完全反转:你期望未在初始化方法中赋值的字段触发诊断,但代码中却是当字段**存在于AlwaysAssigned**时才报告。而AlwaysAssigned包含了字段的初始赋值(比如intContent = -1),所以即使方法里没赋值,这个集合也会包含该字段,导致诊断无法触发。

  2. 数据流分析的范围错误:如果initializationNode是MethodDeclarationSyntax类型,直接传入整个方法节点做数据流分析可能不准确,应该传入方法的Body节点,确保分析覆盖方法内的所有执行逻辑。

  3. 错误使用AlwaysAssigned集合:AlwaysAssigned表示字段在所有代码路径中都被赋值,包括字段的初始值。你需要检查的是初始化方法是否主动写入了该字段,应该使用WrittenSymbols集合,这个集合记录了在分析范围内被显式写入的符号。

修正后的代码

private static void AnalyzeStaticFields(SyntaxNodeAnalysisContext context)
{
    var declaration = (FieldDeclarationSyntax)context.Node;

    if (declaration.Modifiers.Any(SyntaxKind.StaticKeyword))
    {
        if (GetInitializationNode(context, out var initializationNode))
        {
            // 确保分析的是方法体节点
            var methodBody = (initializationNode as MethodDeclarationSyntax)?.Body;
            if (methodBody == null) return;

            DataFlowAnalysis dataFlowAnalysis = context.SemanticModel.AnalyzeDataFlow(methodBody);
            foreach (var variable in declaration.Declaration.Variables)
            {
                var variableSymbol = context.SemanticModel.GetDeclaredSymbol(variable, context.CancellationToken);
                if (variableSymbol == null) continue;

                // 当字段未在初始化方法中被写入时,触发诊断
                if (!dataFlowAnalysis.WrittenSymbols.Contains(variableSymbol))
                {
                    var diagnostic = Diagnostic.Create(FieldRule, variable.GetLocation(), variable.Identifier.ValueText);
                    context.ReportDiagnostic(diagnostic);
                }
            }
        }
    }
}

关键修改说明

  • 替换AlwaysAssigned为WrittenSymbols:精准定位到初始化方法内是否对字段进行了显式赋值,排除字段初始值的干扰。
  • 修正判断逻辑:当字段不在WrittenSymbols中时触发诊断,符合需求预期。
  • 限定分析范围为方法体:确保数据流分析仅针对RuntimeInitializeOnLoadMethod标注方法的内部执行代码,避免无关语法节点的干扰。
  • 增加空值检查:对variableSymbol和methodBody进行空值判断,提升分析器的稳定性。

内容的提问来源于stack exchange,提问作者Ronan Tumelty

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 06:24:25