Suppress some NDepend Issues

Introduction

Despite the fact that we relentlessly improve the NDepend default rules set to avoid false positives, you might not agree with some issues found by NDepend and might want to suppress those. There are various strategies to suppress some NDepend issues:

  • You can use the .NET Base Class Library attribute SuppressMessageAttribute to suppress some issues. This document explains how to achieve that.
  • You can exclude related code from issues inspection with the notmycode / JustMyCode code querying feature explained here.
  • You can choose to modify the culprit rules. With NDepend code rules are just C# LINQ queries querying the code model proposed by NDepend. Thus modifying a rule is an easy task. See more explanations here.
  • You can disable or remove a rule from the NDepend panel Queries and Rules Explorer. You can also achieve that by modifying or removing the concerned XML element <Query Active="True" ...> within the .ndproj or .ndrules XML file that contains the rule.

Suppress some NDepend issues with SuppressMessageAttribute

SuppressMessageAttribute is a class defined in the .NET Base Class Library (in all core and framework versions). It is used to suppress message and issues of FxCop/Code Analysis, Roslyn Analyzer, NDepend and other tools.

This attribute requires the compilation symbol CODE_ANALYSIS to be set on each Visual Studio project relying on it. Without CODE_ANALYSIS symbol defined, the attribute is not compiled and the issues are not ignored.

define conditional compilation symbol CODE_ANALYSIS

If both CODE_ANALYSIS and SuppressMessageAttribute are used correctly in your code but still some issues suppressed are seen as not suppressed, there is maybe a problem with the Rule Id.

  • Does a single activated rule have this Rule Id?
  • Is the Rule Id correctly formatted?
  • Is there more than one activated rule with this Rule Id?

The Analysis logs shows such problem with Rule Id as warnings. Read more about Rule Id below.

Most of the default NDepend rules rely on the code base view JustMyCode. As a consequence issues won't be reported for code that is not yours, like code generated by a tool.

In addition, NDepend also supports issue suppression through the SuppressMessageAttribute (defined in System.Diagnostics.CodeAnalysis).

using System.Diagnostics.CodeAnalysis;
// Suppress issues in the category ".NET Framework Usage" and all sub categories, // in this assembly's namespace types methods and fields [assembly: SuppressMessage("NDepend..NETFrameworkUsage", "", Scope = "deep", Justification="...")]
// Same with more verbose Scope [assembly: SuppressMessage("NDepend..NETFrameworkUsage", "", Scope = "module namespace type method field", Justification="...")] // Suppress all NDepend issues in this assembly [assembly: SuppressMessage("NDepend", "")] // Suppress issues on the method MyClass.Method() by rule ID and ExplicitId // This can be copied in a GlobalSuppression.cs file thanks to the usage of Target [assembly: SuppressMessage("NDepend", "ND2010:AvoidMethodsWithNameTooLong", Target = "MyNamespace.MyClass.Method()")] // Suppress issues for all types declared in the namespace MyNamespace. [assembly: SuppressMessage("NDepend", "ND1306:NestedTypesShouldNotBeVisible", Target = "MyNamespace", Scope = "type")]
namespace MyNamespace {
   // Suppress issues on MyClass by rule ID and ExplicitId (ExplicitId is optional)    [SuppressMessage("NDepend", "ND1203:ClassWithNoDescendantShouldBeSealedIfPossible")]    // Suppress issues on all methods of MyClass by rule ID    [SuppressMessage("NDepend", "ND1701:PotentiallyDeadMethods", Scope = "method")]    // Suppress all NDepend issues on MyClass and its child members    [SuppressMessage("NDepend", "", Scope = "deep")]    class MyClass {       void Method() { }    } }

Scope

[assembly: SuppressMessage("NDepend..NETFrameworkUsage", "", Scope = "deep", Justification="...")]

Scope can take values in:

deep module namespace type method field

If no scope is specified, only issues related to code element tagged will be suppressed. For example when you suppress issues on a class, it suppresses the issues against the class itself. It does not suppress the issues against methods or fields within the class.

The scope value "deep" cannot be used with another scope value. It means:

  • for an assembly: "module namespace type method field"
  • for a namespace: "namespace type method field"
  • for a type: "type method field"
  • for a method: "method"
  • for a field: "field"

Target

[assembly: SuppressMessage("NDepend", "ND2010:AvoidMethodsWithNameTooLong", Target = "MyNamespace.MyClass.Method()")]

The target on which the issues are being suppressed. If the target is not specified, it is set to the target of the attribute.

Notice that Target can be only used for SuppressMessageAttribute tagging an assembly.

The usage of Target might be useful to group all SuppressMessage attributes in the same source file, usually named GlobalSuppression.cs/.vb.

The usage of Target is mandatory when the target is a namespace, because in source code a namespace cannot be tagged with any attribute.

The anonymous namespace is the namespace that contains types declared outside all namespaces. Since the name of the anonymous namespace is a string empty, the string "{anonymous namespace}" must be used instead.

[assembly: SuppressMessage("NDepend", "ND1400:AvoidNamespacesMutuallyDependent", Target = "{anonymous namespace}")]

The target string for any code element can be obtained by right clicking it, menu NDepend > Copy Name to Clipboard.

Copy name to clipboard

The code element target must be declared in the same assembly than the one tagged with SuppressMessageAttribute.

It is possible to target a code element declared in another assembly by prefixing the target name with OtherAssemblyName:.

[assembly: SuppressMessage("NDepend", "ND2010:AvoidMethodsWithNameTooLong", Target = "OtherAssemblyName:MyNamespace.MyClass.Method()")]

Right clicking an NDepend issue, you can use the menu Suppress Issue to generate the SuppressMessage attribute.

Suppress Issue Menu

A form is shown to generate the SuppressMessage attribute code. You can copy to clipboard this code, open the code element declaration and copy it back. In the future we plan a button to automatically insert the SuppressMessage in source code.

NDepend Suppress Issue Form

If you prefer, the form can generate the SuppressMessage attribute with Target, to be copied like in a GlobalSuppression.cs file.

Suppress issue form with Target

The form can also generate the SuppressMessage attribute with Target name prefixed with the assembly name.

Suppress issue form with Target and Assembly

Defining Rule Id and Explicit Id

Since NDepend v2018.2, default rules comes with a rule Id and explicit Id.

// <Name>Avoid types too big</Name>
// <Id>ND1000:AvoidTypesTooBig</Id>
warnif count > 0 from t in JustMyCode.Types where

This Id is mandatory to suppress issues of an NDepend rule by rule Id. The Explicit Id is optional both in the rule definition and for each SuppressMessage.

The Id must be formatted with one or two uppercase letters (usually ND) followed by 4 digits.

The Explicit Id is a camel case string inferred from the rule name.

If two or more rules have the same Id, a warning will be shown in the Analysis logs and SuppressMessage with the shared Rule Id are ignored.

Suppressing Issues for Categories of Rules

Instead of using SuppressMessage attribute with a rule-id, you can suppress issues for all rules in a category. For example here all issues of rules in the category .NET Framework Usage, and all sub-categories of this category, will be suppressed.

[assembly: SuppressMessage("NDepend..NETFrameworkUsage", "", Scope = "deep", Justification="...")]

The category name is obtained by right-clicking the group of rules in the UI, menu Copy to Clipboard SuppressMessage for Rules in this Group and sub-Group.

Rule Category Menu

Suppressing Issues related to Baseline

With NDepend a rule can take account of baseline. Such rule can be found for example in the categories API Breaking Changes or Code Smells Regression.

As a consequence an issue can be related to a code element defined in the baseline and removed since, like when reporting an API breaking change because of a public type removed. To remove such issue, the SuppressMessage target must be the parent of the removed code element, and the scope must be adjusted.

For example in the screenshot below the public class FirebirdDriver has been removed since the baseline and the related SuppressMessage target is the parent namespace NHibernate.Driver, with scope set to "type":

Suppress Issue on a Baseline Element

Troubleshoot SuppressMessage problems with analysis logs

Above, we explain that when two or more rules have the same rule Id, an analysis warning is emitted in the warning log and SuppressMessage attributes with this rule Id are not taken account.

This is a general advice to troubleshoot issues that should be suppressed with SuppressMessage but that are not seen as suppressed. Look at analysis logs, all possible warnings about SuppressMessage will be there, including:

  • For a SuppressMessage attribute, Rule Id or Explicit Id specified not well formatted
  • Rules must have distinct Ids and explicit Ids
  • For a SuppressMessage attribute, no rule found with the specified Rule Id or Explicit Id
  • For a SuppressMessage attribute, the Explicit Id specified doesn't correspond to the one for the specified Rule Id
  • For a SuppressMessage attribute, invalid Scope string
  • For a SuppressMessage attribute, cannot resolve Target code element from the Target string
  • For a SuppressMessage attribute, the scope is incompatible with the Target. For example scopes module and namespace are incompatible if the target element is a type, a method or a field.

List Suppressed Issues

Suppressed issues can be queried with this code query:

    context.IssuesSet.AllSuppressedIssues

The dashboard shows the number of suppressed issues and clicking this number leads to edit a query that lists them:

Dashboard with Suppress Issues

When viewing a rule, a suppressed issues container can be unfold:

Rule Suppressed Issues