C# 如何在静态代码分析器实用程序中找到NullReferenceException的潜在点?

C# 如何在静态代码分析器实用程序中找到NullReferenceException的潜在点?,c#,reflection,code-analysis,software-quality,C#,Reflection,Code Analysis,Software Quality,我们正在开发一个静态代码分析工具,旨在通过一些提示改进代码 我们希望找到开发人员忘记检查变量、属性或方法返回的可空性并通过点表示法访问成员的地方,因为它可能会遇到NullReferenceException 例如,此代码: class Program { static void Main(string[] args) { var human = new Human(); if (human.Name.Length > 10)

我们正在开发一个静态代码分析工具,旨在通过一些提示改进代码

我们希望找到开发人员忘记检查变量、属性或方法返回的可空性并通过点表示法访问成员的地方,因为它可能会遇到NullReferenceException

例如,此代码:

class Program
{
    static void Main(string[] args)
    {
        var human = new Human();
        if (human.Name.Length > 10)
        {
            // Jeez! you have a long name;
        }
    }
}

public class Human
{
    public string Name { get; set; }
}
我们使用Mono.Cecil,在给定的程序集中找到所有类型的所有方法的主体,对于每个方法主体,我们找到它的指令,然后检查Callvirt操作。但这并不支持这个例子:

class Program
{
    static string name;

    static void Main(string[] args)
    {
        if (name.Length > 10)
        {
        }
    }
}
我们如何找到对给定的可空类型的成员(变量、字段、属性、方法)的所有访问

更新: 事实上,我们正在搜索表示IL中给定变量的成员访问权限的操作码。这是可能的吗?

帮助文档记录了以下内容:

下列Microsoft中间语言(MSIL)说明 抛出
NullReferenceException
callvirt
cpblk
cpobj
initblk
ldelem.
ldelema
ldfld
ldflda
ldind.
ldlen
stelem.
stfld
stind.
抛出
,和
取消装箱

这些问题可分为以下几点:

  • 数组访问:
    ldelem
    ldelema
    ldlen
    stelem
    。数组引用不能为
    null
  • 非数组成员访问:
    ldfld
    ldflda
    stfld
    。对象引用不能为
    null
  • 方法访问:
    callvirt
    。对象引用不能为
    null
    。属性访问也是方法访问,因为它调用属性getter/setter
  • 指针/引用访问:
    cpblk
    cpobj
    initblk
    ldind
    stind
    。指针/引用不能为
    null
    。在经过验证的托管代码中,这些操作码通常不会在其参数可能为
    null
    的上下文中使用
  • 正在引发异常:
    throw
    。异常引用不能为
    null
  • 取消装箱:
    取消装箱
    。对象引用不能为
    null
将操作码参数追溯到变量/字段是另一个问题。这可能是任意复杂的,因为操作码只关心堆栈上的内容,而不关心它来自何处。在某些情况下,您可能正在处理表达式(
a[0].SomeMethod().FieldAccess
,其中
a
a[0]
a[0]中的任何一个。SomeMethod()
在不应该为空时可以为
null

您最好不要在IL级别上检查这一点,而是使用它在语言级别上为您提供分析。通过访问源代码,生成高质量反馈要简单得多

即使如此,也要注意,针对可空性的高质量静态分析并不容易。您当然可以编写一个分析器,在程序员可能忘记检查的任何情况下,它都会愉快地发出警告,但是如果程序员被迫插入大量多余的检查来检查显然从不为空的引用,那么这样的分析器几乎就没用了。如果您将此与TFS签入策略联系在一起,那么请准备好接受来自开发人员和管理人员的死亡威胁,他们希望了解生产率为何大幅下降


现有的工具如Resharper增加了很多用于控制分析的功能,这是有原因的,而且C#本身也增加了可空性检查。在重新发明轮子之前,请先了解您将要从事的工作。

您想创建一个使用反射进行静态代码分析的工具,这不是一个小壮举,但您有一个关于如何使用反射的基本问题?我认为你在这件事上是本末倒置。我建议你首先学习所有关于反思的知识。然后,您将需要了解如何销毁一个方法,以便您的代码可以找到类似上述情况(这是较难的部分)。哦,是的,在那之后,你必须以某种方式通知用户(不确定这是内联的还是通过控制台输出的)。顺便说一句,已经有很多工具在做这些事情了。像这样的工具会让你知道(内联)是否有可能出现NullReferenceException等情况。@Igor我们已经使用签入策略开发了基于TFS的代码分析/质量。目前,它检查了我们定义的180多条规则,以提高由大约15名开发人员开发的多个大型代码库的质量。这个问题是关于我们想要添加的一个新规则-空检查应该在需要时出现,以防止NullReferenceException。我们开发了一个静态代码分析器PVS Studio(C++,C#):这就是为什么我想给出另一个答案。为一些内部任务制作分析器有意义吗?最有可能的是,这将是一件不太舒服的事情,此外,它会分散开发人员对其主要任务的注意力。我建议将此任务重定向给某人。例如,对于我们:)我们也进行自定义诊断