Example: Specify Justification for SuppressMessage Attributes

When SuppressMessageAttribute is used in code to override an FxCop rule, the programmer may optionally specify the Justification property to explain the reason for using the attribute. This is a good practice which the following rule will help enforce.

The implementation requires numerous Check methods to be overridden because the attribute SuppressMessageAttribute can be placed on various kinds of targets in the source code.

Rule XML:

<Rule TypeName="SpecifySuppressMessageJustification" Category="Tutorial" CheckId="TT1035">
  <Name>Specify SuppressMessage justification</Name>
  <Description>
    The SuppressMessage.Justification property should be set to an explanation
    of why you are suppressing an FxCop rule.
  </Description>
  <Url></Url>
  <Resolution>Specify the Justification property.</Resolution>
  <MessageLevel Certainty="95">Warning</MessageLevel>
  <Email></Email>
  <FixCategories>NonBreaking</FixCategories>
  <Owner></Owner>
</Rule>

Rule Implementation:

using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.FxCop.Sdk;

namespace TutorialRules
{
  class SpecifySuppressMessageJustification : BaseIntrospectionRule
  {
    public SpecifySuppressMessageJustification()
      :
      base("SpecifySuppressMessageJustification", "TutorialRules.TutorialRules",
      typeof(SpecifySuppressMessageJustification).Assembly)
    {
    }

    public override ProblemCollection Check(ModuleNode module)
    {
      AssemblyNode assmbly = module as AssemblyNode;
      if (assmbly != null)
      {
        CheckSuppressMessage(assmbly.ModuleAttributes);
      }

      CheckSuppressMessage(module.Attributes);
      return this.Problems;
    }

    public override ProblemCollection Check(TypeNode type)
    {
      CheckSuppressMessage(type.Attributes);
      return this.Problems;
    }

    public override ProblemCollection Check(Member member)
    {
      Method methd = member as Method;
      if (methd != null && methd.ReturnAttributes != null)
      {
        CheckSuppressMessage(methd.ReturnAttributes);
      }

      CheckSuppressMessage(member.Attributes);
      return this.Problems;
    }

    public override ProblemCollection Check(Parameter parameter)
    {
      CheckSuppressMessage(parameter.Attributes);
      return this.Problems;
    }

    public void CheckSuppressMessage(AttributeNodeCollection attributes)
    {
      foreach (AttributeNode attr in attributes)
      {
        if (attr.Type == FrameworkTypes.SuppressMessageAttribute)
        {
          Literal lit = attr.GetNamedArgument(Identifier.For("Justification")) as Literal;
          if (lit == null || string.IsNullOrEmpty((string)lit.Value))
          {
            this.Problems.Add(new Problem(this.GetResolution()));
          }
        }
      }
    }
  }
}