领先技术

静态代码分析和代码约定

Dino Esposito

image: Dino Esposito
对于许多人来说,很难相信没有以往任何时候都无法打印应用程序的整个源代码时一次读取从上到下,捕获错误或可能出错。现代软件的复杂性使这种方法不切实际的人 — — 而不是为某些类型的智能软件,如静态分析工具。

静态分析的软件组成,推断出的一段从其指令的代码的行为。静态分析工具通过逐步构建基础知识,使用它来证明语句和相应的输出,向右或错误执行其检查源代码。静态分析不实际执行代码。 它只需读取行,然后计算出的事情。何种操作?

一般情况下,静态分析可以识别可能在代码中的 bug,以及指示某些代码段匹配的期望和规范的程度。

这段时间我们已经知道,— — 至少最早为很好通过亚伦生产的变体桥牌 — 没有自动和完全可靠的方法来确定是否给定的程序将终止没有错误。在任何情况下,计算机科学主要基于近似值,并正在注意可能有一些线条的周围的错误是一个有价值的帮助。扩展此帮助现代项目的大小,您可以看到真正的价值。静态分析工具可能不会让您绝对 certainties,但在编写您的类时,请使用实时,它可以提供即时反馈有关内容可能会在实现中的错误。

静态分析和测试

是基本区别测试和静态分析。作为开发人员,您正在编写测试,但被动这样的静态分析。如果测试实际上没有完全遮盖重要条件,或不检查它们具有很大的值,则结果将不会有意义。静态分析工具使您有关事实的警告 (因为该工具了解它们) 的违反某些配置的内部规则。一般情况下,从静态分析获取几乎没有任何警告是质量的软件更好地指示。另一方面,获取警告不自动意味着您的软件是有错误的首次运行时将会失败。静态分析可能会检测到硬盘问题、 极端情况也可能会使您的应用程序崩溃的错误。与测试、 静态分析可以捕捉缺陷很早在开发阶段,从而限制对整个项目的软件错误的影响。

类型的静态分析器

静态分析都有很多方面和多个不同级别的实现。一种基本类型的静态分析器的语言编译器。编译器经过您的源代码,并与该语言的语法规则进行匹配。这是分析的第一步。现代的编译器,但是,做得更多。

当在派生类中所要求的代码合同和最新的 C# 编译器例如,检测到违反 Liskov 原则。此编译器通常可以指出未使用的变量的匹配项。但是,何种编译器检测到并分类为警告不会一定才会被视为错误。尽管如此,编译器将不同的步骤,您必须执行。这可能需要一段时间,具体取决于项目和环境。

FxCop ; 更好地还,Visual Studio 2010 年,该代码分析功能之类的工具执行代码的详细分析中,可以配置为运行按需或在每个版本中,图 1显示。

Code Analysis Settings in a Visual Studio 2010 Project

图 1Visual Studio 2010年项目中的代码分析设置

此外,您可以以声明方式设置要处理您的代码时所采用的规则。图 2显示长启用 Visual Studio 2010年代码分析中的所有规则选项时,您可能会收到的警告的列表的一个示例。请注意这些警告一些非常具体,并使代码更清晰和更 adherent microsoft 非常有用。NET 框架指导原则。


Warnings Received When All Rules Are Enabled(单击进行缩放)

图 2时启用了所有规则,将收到警告

有关静态分析的关键一点是自动工具绝对诚实,为您提供严格基于规则的冲突的警告。检测到的规则冲突不一定错误; 但如果一个 bug 与冲突,它可能会显示在边缘的情况下,并完全遵照 Murphy 定律 — 只是当它将做最大损坏。

除了按需工具 (如编译器和 FxCop 类似设施,另一个类别的工具可以为您提供很多反馈 — 但它们以异步方式起作用。此类别所属的 ReSharper,它提供了相同类型的有用的建议作为代码分析,但动态您键入时。它还提供您编辑代码,单击一次或两个的代价。ReSharper 检测,例如,未赋值的变量、 无法访问的代码、 可能的 null 引用和各种如 LINQ 表达式中的已修改闭包在构造函数和访问虚调用的代码 smells。更重要的是,ReSharper 允许您实现您自己的代码 smells 自动查找并按您键入智能地替换它们。有关详细信息和详细的分步示例的 ReSharper 结构搜索和替换,阅读博客张贴内容在bit.ly/eCMvCL

最后,在静态分析。NET 框架 4 到 Visual Studio 2010 年还将使用静态检查器工具创建的代码合同团队。

在操作中的静态检查器

加上代码合同,Microsoft 提供了静态检查工具,它可以经过您的代码,即使没有对其进行编译,并突出显示代码合同无法验证或只是无法证明正确或错误。只有在 Visual Studio 2010年特优或最高或 Visual Studio 团队系统 2008年,您可以获取静态检查器。这些版本要求与代码分析功能的要求 — — 即,这些功能都位于 Visual Studio 的专业人员或速成版。

中间语言 rewriter 中,如静态检查器增强了 Visual Studio 2010年单独下载。您可以获得最新的代码合同位,从bit.ly/fF3wzl。您需要显式启用静态检查基于每个项目配置,如中所示图 3

Enabling Static Checking of Code Contracts in Visual Studio 2010

图 3Visual Studio 2010 年启用静态检查代码的合同

静态检查器可以在后台运行如果您愿意,并可以明确地显示每个警告的波形曲线。后台执行意味着静态检查计划按编译代码更改编译器与并行运行。

您可以查找,以及明确合同隐式使用静态检查器。显式的合同是在类方法中,如前提条件后, 置条件或不变声明任何合同。此外,静态检查器还可以考虑一些内置的代码合同,并检查是否数组索引始终保持在数组界限,是否使用任何空引用或任何被零除会。您可以控制通过复选框中所示的隐式代码合同图 3。请注意启用隐式代码合同可能充斥大量消息,警告您输出窗口。您可能不希望这样做,和可能不之后开始。以下是代码的上有隐式数组界限义务合同时将捕获为潜在错误的示例:

var numbers = new int[2];
numbers[3] = 0;

大部分的静态检查器中,不过,导致它显式合同,如前置条件和后置条件中使用。

显式合同

假设您有下面的代码中的方法之一:

var orderId = GetLatestOrderId(); 
ProcessOrder(orderId);

变量是从函数调用,并且随后将传递到另一种方法进行进一步处理。 没有多任何静态检查器可以执行以证明这些语句,向右或不明确的合同中的某些信息不正确。 另一方面,如果 GetLatestOrderId 方法公开后置有意义条件,下面的代码所示,检查程序可能能够证明次后续调用是否有效:

public int GetLatestOrderId()
{
  Contract.Ensures(Contract.Result<int>() >0);
  ...
return n;
}

GetLatestOrderId 方法显式地声明它将返回一个值大于零。 检查器使其密码,因为它获取信息的这段并将其添加到其知识库。 后来又时发现使用 GetLatestOrderId 方法的返回值使用显式的前提条件的另一种方法的输入,检查器可以合理尝试该操作符合已声明的合同。 让我们来看,请考虑以下前提条件合同:

public void ProcessOrder(int orderId)
{
  Contract.Requires<ArgumentException>(orderId >0);
  ...
}

这些两个显式协定向证明合同检查提供足够的信息。 在这种情况下,您将不会获得任何额外的警告。 但是,如果这些合同丢失了一些呢? 静态检查返回的输出类似于中看到的内容图 4。 检查器检测到的比如说,某个方法具有需要合同,从没有说任何有关其返回输出的另一个接收数据。

Unproven Contracts

图 4未经验证的合同

既然要获得最大的静态检查器,则必须使用整个代码中的所有代码合同,它应该是清楚了。 更明确的合同,则将在中,静态检查器可以更可靠。

假定并断言

有时,但是,必须与其他人已经编写了一些并不能更新的旧代码集成您的新代码。 如果与原有代码不包含任何合同,您将获得令人讨厌的静态检查的警告。 代码合同 API 提供了这样一种解决方法。

未经验证的合同警告实质上是源于信息不足--检查器找不到所需的信息。 但是,作为开发人员,您可以提供更多详细信息--具体来说,假设。 可以查看图 5

A Warning from the Static Checker

图 5静态检查警告

您会看到警告有关可能的空引用的工具提示。 很显然,该变量上下文不具有已分配的情况下使用。 由谁负责实际工具提示? 它是检查器还是其他内容吗?

在这种情况下,工具提示将来自于 ReSharper,其分析引擎正确确定可能的空引用。 为什么不要我们收到类似的邮件从检查器? 这是由于中的第一行图 5

Contract.Assume(context != null);

使用此指令,保证向检查的变量上下文永远不为空。 检查工具只信任您,并向其知识库的信息。 ReSharper 当前不提供完全支持。NET 代码合同,解释了为什么它仍为您提供一条警告。 另一方面,ReSharper 不支持自己的批注,您可以使用很多相同的方式为假定集。 请参阅bit.ly/lVSnkj的更多详细信息。

最佳使用的静态分析

静态分析很困难,而且也可能不是精确的数字。 它经常会出现具有最佳的本意,只是为了找出它显著降低了生成过程的合同信息填充您的代码。 有几个考虑优化使用合同和后续分析的方法。

首先,您可能希望创建一个特殊的生成配置并启用上的静态检查。 切换到该定期、 获取反馈并应用它。 完成后,您将移回生成照常没有额外的负担,静态分析的解决方案。

第二,您可以尝试使用合同逐段。 应用合同广泛地在代码中,但是然后禁用程序集级别的合同。 要做到这一点只需将以下属性添加到该程序集的属性:

[assembly: ContractVerification(false)]

接下来,则重新启用检查只在您在当前集中的合同: 类、 方法或程序集。 您可以使用相同的属性值为 true。

总结

静态分析是一种技术,旨在评估源代码的正确性,但不运行它。 有几个工具来执行此操作以多个范围。 一个是只是编译器。 另一个分析工具是静态检查 — 通常与生成过程集成的可执行文件。 在中。NET 框架中,特殊的静态检查器工具可以学习关于您的代码从代码合同。 检查器,然后计算这些事实并突出显示可能的错误和合同的冲突。

每次当复杂性不断增加,并开发团队始终运行充足的时间,集成的静态分析在版本中保存的时间,更重要的是,保存您从命中您的软件只需在角情况下的严重错误。

Dino Esposito 是《Programming Microsoft ASP.NET MVC》(Microsoft Press,2010 年)一书的作者,也是《Microsoft .NET:Architecting Applications for the Enterprise》(Microsoft Press,2008 年)的合著者。Esposito 定居于意大利,经常在世界各地的业内活动中发表演讲。有关他的情况,请访问 Twitter twitter.com/despos

衷心感谢以下技术专家对本文的审阅: Manuel Fahndrich