How can I find which getters properties have side effects using NDepend?

A known issue with using VisualStudio is the cryptic calling of property recipients. If they have side effects (the most common of the forms if (foo == null) foo = new foo(); return foo;), then the fact that the Locals and Watch debug windows invoke properties β€” even without hitting any breakpoints β€” can lead to unexpected debugging consequences.

There is a simple solution: just mark the property with an attribute

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]

So, how can I find getters that can have side effects in a large code base?

NDepend is the tool of choice for this kind of thing: using my CQL language, I can find all the properties that, for example, directly change the state of my containing instance:

         SELECT METHODS FROM ASSEMBLIES "FOO" 
         WHERE IsPropertyGetter AND ChangesObjectState 

It only finds those getters that directly change the field: how can I find those that indirectly change it, for example. by calling a method Initialize()?

+3
source share
1 answer

Joel, this is possible thanks to Code Query through LINQ (CQLinq) capabilities. Here is a CQLinq query that detects deep volatility for getters properties. For each getter that causes variability, a code request shows a set of assigned fields.

// Restrict the iteration only on property getters
// that are changing states or that call a method that changes state
let propertyGetters = Application.Methods.Where(m => m.IsPropertyGetter)

let methodsThatChangeState = 
  Application.Methods.Where(m => m.ChangesObjectState || m.ChangesTypeState)

from m in propertyGetters.DepthOfIsUsingAny(methodsThatChangeState).DefinitionDomain
          .Union(propertyGetters.Intersect(methodsThatChangeState))

// Find all methods called directly or indirectly by the property getter
let methodsCalledIndirectly = 
        m.MethodsCalled.FillIterative(
           methods => methods.SelectMany(m1 => m1.MethodsCalled))
        .DefinitionDomain
        .Union(m.ToEnumerable())

// Gather all field assigned that are not generated by the compiler
let fieldsAssigned = methodsCalledIndirectly
                     .SelectMany(m1 => m1.FieldsAssigned)
                     .Where(f => !f.IsGeneratedByCompiler)

where fieldsAssigned.Any()
orderby fieldsAssigned.Count() descending 
select new { m, fieldsAssigned }

, , , , , , ( DepthOsIsUsingAny()).

getter , ( FillIterative()), , .

:

enter image description here

+1

Source: https://habr.com/ru/post/1755502/


All Articles