Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NDepend CQL Query for missing IDisposable implementation

I realize that the query this question is looking for won't be enough to find every little problem with IDisposable implementations, but every early warning counts, so I'll take what I can get.

I'd like to know if anyone has come up with a CQL query for NDepend that will list all classes that doesn't implement IDisposable, but has one or more fields that does. A class could end up on the resultlist of this query either through a bug (ie. someone forgot to check the field types for IDisposable implementations), or through code evolution (ie. a class used in a field somewhere gets IDisposable tacked on at a later date without all usages being updated).

The simple query to find all classes that doesn't implement IDisposable is:

SELECT TYPES WHERE !Implement "System.IDisposable"

However, this will of course not check if the class should implement IDisposable for the above rule.

Does anyone have such a query? I'm still getting to grips with CQL so this part eludes me.

like image 969
Lasse V. Karlsen Avatar asked Nov 23 '08 19:11

Lasse V. Karlsen


1 Answers

Lasse, thanks to CQLinq (Code Rule over LINQ) capabilities matching types that should implement IDisposable is now possible. Actually two related default rules are now provided, and you can easily write your own related rules:

  • Types with disposable instance fields must be disposable
  • Disposable types with unmanaged resources should declare finalizer

// <Name>Types with disposable instance fields must be disposable</Name>
warnif count > 0

let iDisposable = ThirdParty.Types.WithFullName("System.IDisposable").FirstOrDefault() 
where iDisposable != null // iDisposable can be null if the code base doesn't use at all System.IDisposable

from t in Application.Types where 
   !t.Implement(iDisposable) && 
   !t.IsGeneratedByCompiler 

let instanceFieldsDisposable = 
    t.InstanceFields.Where(f => f.FieldType != null &&
                                f.FieldType.Implement(iDisposable))

where instanceFieldsDisposable.Count() > 0
select new { t, instanceFieldsDisposable }

// <Name>Disposable types with unmanaged resources should declare finalizer</Name>
// warnif count > 0
let iDisposable = ThirdParty.Types.WithFullName("System.IDisposable").SingleOrDefault()
where iDisposable != null // iDisposable can be null if the code base deosn't use at all System.IDisposable

let disposableTypes = Application.Types.ThatImplement(iDisposable)
let unmanagedResourcesFields = disposableTypes.ChildFields().Where(f => 
   !f.IsStatic && 
    f.FieldType != null && 
    f.FieldType.FullName.EqualsAny("System.IntPtr","System.UIntPtr","System.Runtime.InteropServices.HandleRef")).ToHashSet()
let disposableTypesWithUnmanagedResource = unmanagedResourcesFields.ParentTypes()

from t in disposableTypesWithUnmanagedResource
where !t.HasFinalizer
let unmanagedResourcesTypeFields = unmanagedResourcesFields.Intersect(t.InstanceFields)
select new { t, unmanagedResourcesTypeFields }
like image 82
Patrick from NDepend team Avatar answered Oct 16 '22 12:10

Patrick from NDepend team