Wrong usage of CannotDecreaseVisibilityAttribute
NDepend.Attributes.CannotDecreaseVisibilityAttribute (from NDepend.API.dll, or declared in your own code) marks elements whose visibility is not optimal but shouldn't be modified — e.g. elements consumed through reflection, mocking, serialization, designers, COM, or reached by test code. It silences the not-optimal-visibility rules and expresses: Don't change the visibility else something will be broken.
This rule matches elements tagged with this attribute whose visibility is nevertheless already optimal.
When an element is used by test code, its optimal visibility is recomputed without taking test code users into account. If this visibility is more restrictive than the actual one, the element is exposed on purpose for tests: the attribute usage is valid and the element is not matched.
This rule matches elements tagged with this attribute whose visibility is nevertheless already optimal.
When an element is used by test code, its optimal visibility is recomputed without taking test code users into account. If this visibility is more restrictive than the actual one, the element is exposed on purpose for tests: the attribute usage is valid and the element is not matched.
How to fix
Remove the now-useless CannotDecreaseVisibilityAttribute tagging of matched elements. Severity is Low: more an advice than a problem.
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>Wrong usage of CannotDecreaseVisibilityAttribute</Name>
// <Id>ND1809:WrongUsageOfCannotDecreaseVisibilityAttribute</Id>
warnif count > 0
let tAttr = Types
.WithFullName("NDepend.Attributes.CannotDecreaseVisibilityAttribute")
.FirstOrDefault()
where tAttr != null
// Rank visibilities: the higher the rank, the more restrictive.
let rank = new Func<Visibility, int>(v =>
v == Visibility.Private ? 4 :
v == Visibility.ProtectedAndInternal ? 3 :
v == Visibility.Internal || v == Visibility.Protected ? 2 :
v == Visibility.ProtectedOrInternal ? 1 : 0)
// Estimate the optimal visibility of an element declared in the type pt
// (null for non-nested types) and in the assembly asm, given the types
// of its non-test users.
let optimal = new Func<IType, IAssembly, IType[], Visibility>(
(pt, asm, users) =>
pt != null && users.All(u => u == pt || u.ParentType == pt ||
pt.NestedTypes.Contains(u)) ?
Visibility.Private :
pt != null && users.All(u => u == pt || u.DeriveFrom(pt)) ?
Visibility.Protected :
users.All(u => u.ParentAssembly == asm) ? Visibility.Internal :
Visibility.Public)
// The attribute usage is valid when the element is used by test code
// and its visibility could be decreased if test code users are ignored.
// userTypes are the types of all users, test code users included.
let validForTests = new Func<IMember, IEnumerable<IType>, bool>(
(x, userTypes) =>
userTypes.Any(u => u.IsTestCode) &&
rank(optimal(x.ParentType, x.ParentAssembly,
userTypes.Where(u => !u.IsTestCode).ToArray()))
> rank(x.Visibility))
// Only iterate the elements tagged with the attribute: O(#tags)
let tagged = tAttr.TagsWithMeAsAttribute
.Select(tag => tag.CodeElementTagged)
.Where(x => !x.IsTestCode && !x.IsThirdParty)
.ToArray()
// Get types that do a wrong usage of CannotDecreaseVisibilityAttribute
let types = from t in tagged.Where(x => x.IsType).Select(x => x.AsType)
where
( t.Visibility == t.OptimalVisibility &&
!validForTests(t, t.TypesUsingMe.Where(u => u != t)) ) ||
// Static types that define only const fields cannot be seen as
// used in IL code. They don't need to be tagged with the attribute.
(t.IsStatic && t.NbMethods == 0 && !t.Fields.Any(f => !f.IsLiteral))
select t
// Get methods that do a wrong usage of CannotDecreaseVisibilityAttribute
let methods = from m in tagged.Where(x => x.IsMethod)
.Select(x => x.AsMethod)
where m.Visibility == m.OptimalVisibility &&
!validForTests(m, m.MethodsCallingMe.Select(c => c.ParentType)
.Distinct())
select m
// Get fields that do a wrong usage of CannotDecreaseVisibilityAttribute
let fields = from f in tagged.Where(x => x.IsField).Select(x => x.AsField)
where f.Visibility == f.OptimalVisibility &&
!validForTests(f, f.MethodsUsingMe.Select(u => u.ParentType)
.Distinct())
select f
from member in types.Cast<IMember>().Concat(methods).Concat(fields)
select new {
member,
Debt = 30.ToSeconds().ToDebt(),
Severity = Severity.Low
}
//<Expl>
// The *{0}* shouldn't be tagged with *CannotDecreaseVisibilityAttribute*
// because its visibility is already optimal, even when its test code
// users are not taken into account.
//</Expl>
//<Desc>
// **NDepend.Attributes.CannotDecreaseVisibilityAttribute** (from
// *NDepend.API.dll*, or declared in your own code) marks elements whose
// visibility is not optimal but shouldn't be modified — e.g. elements
// consumed through reflection, mocking, serialization, designers, COM,
// or reached by test code. It silences the not-optimal-visibility rules
// and expresses: **Don't change the visibility else something will be
// broken**.
//
// This rule matches elements tagged with this attribute whose visibility
// is nevertheless already optimal.
//
// When an element is used by test code, its optimal visibility is
// recomputed without taking test code users into account. If this
// visibility is more restrictive than the actual one, the element is
// exposed on purpose for tests: the attribute usage is valid and the
// element is not matched.
//</Desc>
//<HowToFix>
// Remove the now-useless *CannotDecreaseVisibilityAttribute* tagging of
// matched elements. Severity is **Low**: more an advice than a problem.
//</HowToFix>
Open in the interactive Rules Explorer · All default rules
Visibility: all 12 items
- Methods that could have a lower visibility ND1800
- Types that could have a lower visibility ND1801
- Fields that could have a lower visibility ND1802
- Types that could be declared as private, nested in a parent type ND1803
- Avoid publicly visible constant fields ND1804
- Fields should be declared as private or protected ND1805
- Constructors of abstract classes should be declared as protected or private ND1806
- Avoid public methods not publicly visible ND1807
- Event handler methods should be declared as private or protected ND1808
- Wrong usage of CannotDecreaseVisibilityAttribute ND1809
- Exception classes should be declared as public ND1810
- Methods that should be declared as 'public' in C#, 'Public' in VB.NET