1

I'm struggling with NDepend a bit. It's a bit hard to explain. I have a method in my codebase (lets call that method 'TheMethod') that mustn't be called by other methods of a certain kind (lets call this kind 'TheKind'), unless they are decorated with some attribute ('TheAttr'), directly or indirectly; If indirectly, any hop decorated with 'TheAttr' should result in no violation of the indirect usage.

I'll visualize some scenarios with an "->" arrow meaning "uses", and methods having the aforementioned attribute with TheAttr with "[TheAttr]", and the word "FAIL" if the rule should be violated / "SUCCESS" if the rule should not be violated.

So...

I can write a CQLinq query that triggers for all methods of 'TheKind' using 'TheMethod' directly or indirectly. I can also exclude the methods from the result which have 'TheAttr'.

somemethod -> TheMethod      FAIL
somemethod[TheAttr] -> TheMethod     SUCCESS

Getting indirect usages into the rule is easy as well:

somemethod -> method1 -> method2 -> TheMethod     FAIL
somemethod[TheAttr] -> method1 -> method2 -> TheMethod    SUCCESS

Now, what I want, is this:

somemethod -> method1[TheAttr] -> method2 -> TheMethod    SUCCESS

and

somemethod -> method1 -> method2[TheAttr] -> TheMethod    SUCCESS

So, in other words, any intermediate caller that has the decoration should result in valid usages of 'TheMethod' / calls "through" a valid usage should be valid, as well.

Can this be checked with NDepend? I experimented with FillIterative but without luck so far.

Thanks, Tim

PS.: Here is my current attempt:

    warnif count > 0 
let mcalling = Methods.WithFullName("My.Namespace.MyType.get_SomeProperty()").SingleOrDefault().MethodsCallingMe.ToList()
let domain = mcalling.FillIterative(callers => // Unique loop, just to let a chance to build the hashset.
                                      from o in (new object()).ToEnumerable()
                                      let hashset = callers.ToHashSet() // Use a hashet to make Intersect calls much faster!
                                      from m in Methods.UsingAny(callers).Except(callers) 
                                      where !m.HasAttribute("My.Namespace.NDependIgnore.MayUsePropAlthoughAsync".AllowNoMatch())
                                      select m
                                   )

let indirectcallers = domain.DefinitionDomain.Where(m1 => m1.IsAsync).ToArray()  // Avoid double enumeration

from m in indirectcallers
let depth = m.DepthOfIsUsing("My.Namespace.MyType.get_SomeProperty()")
where depth >= 0
select new 
{ 
  Method=m, 
  Depth=depth, 
  Level=domain[m]
}
  • Did you try play with the query proposed here? (the sceond one that uses FillIterative()) http://stackoverflow.com/a/13419075/27194 what about putting a condition in ...callers.SelectMany(m1 => m1.MethodsCallingMe)... – Patrick from NDepend team Nov 24 '16 at 13:12
  • 1
    Yes, I indeed played with that query, to no avail yet. I'll update my question with my current attempt. – Dr. Tim dos Santos Nov 25 '16 at 06:17

0 Answers0