Mark attributes with AttributeUsageAttribute

Rule ND2203 .NET Framework Usage / System

Mark custom attributes with AttributeUsageAttribute to indicate where they can be applied, per their meaning (e.g. a type-maintainer attribute belongs on classes, enumerations and interfaces, not methods or properties). Valid targets come from the System.AttributeTargets enumeration; omitting the attribute means All targets.

Not matched: abstract attribute classes (usage can be deferred to derived classes) and classes whose base is tagged (usage is inherited).

How to fix

Specify targets via AttributeUsageAttribute with the proper AttributeTargets values.

CQLinq source

This rule is written in CQLinq, C# LINQ over the NDepend code model. It ships with every new NDepend project: you can read it, adapt it, or use it as a starting point for your own custom rules.

// <Name>Mark attributes with AttributeUsageAttribute</Name>
// <Id>ND2203:MarkAttributesWithAttributeUsageAttribute</Id>

warnif count > 0
from t in JustMyCode.Types where 
   
    t.DeriveFrom ("System.Attribute".AllowNoMatch())
&& !t.HasAttribute ("System.AttributeUsageAttribute".AllowNoMatch()) 

// AttributeUsageAttribute can be deferred to classes that derive from an abstract attribute class
&& !t.IsAbstract

// AttributeUsageAttribute can de inherited from a base attribute class (that is not System.Attribute)
&& !t.BaseClasses.Any(c => 
        c.FullName != "System.Attribute" && 
        c.HasAttribute ("System.AttributeUsageAttribute".AllowNoMatch()))

select new {
   t,
   Debt = 5.ToMinutes().ToDebt(),
   Severity = Severity.High
}

//<Expl>
// The *attribute {0}* should be annotated with *AttributeUsageAttribute*
// to specify where in the source code the custom attribute can be applied.
//</Expl>

//<Desc>
// Mark custom attributes with **AttributeUsageAttribute** to indicate where
// they can be applied, per their meaning (e.g. a type-maintainer attribute
// belongs on classes, enumerations and interfaces, not methods or
// properties). Valid targets come from the **System.AttributeTargets**
// enumeration; omitting the attribute means **All** targets.
//
// Not matched: abstract attribute classes (usage can be deferred to derived
// classes) and classes whose base is tagged (usage is inherited).
//</Desc>

//<HowToFix>
// Specify targets via *AttributeUsageAttribute* with the proper
// *AttributeTargets* values.
//</HowToFix>

.NET Framework Usage / System: all 12 items