Я немного борюсь с NDepend. Это немного сложно объяснить. В моей кодовой базе есть метод (давайте назовем этот метод «TheMethod»), который не должен вызываться другими методами определенного типа (давайте назовем этот тип «TheKind»), если они не украшены каким-либо атрибутом («TheAttr» ), прямо или косвенно; Если косвенно, любой прыжок, украшенный «TheAttr», не должен приводить к нарушению косвенного использования.
Я буду визуализировать некоторые сценарии со стрелкой «->», означающей «использует», и методами, имеющими вышеупомянутый атрибут с TheAttr с «[TheAttr]», и словом «FAIL», если правило должно быть нарушено / «SUCCESS», если правило не должно нарушаться.
So...
Я могу написать запрос CQLinq, который срабатывает для всех методов «TheKind», используя «TheMethod» прямо или косвенно. Я также могу исключить из результата методы, у которых есть «TheAttr».
somemethod -> TheMethod FAIL
somemethod[TheAttr] -> TheMethod SUCCESS
Получить косвенные использования в правиле также легко:
somemethod -> method1 -> method2 -> TheMethod FAIL
somemethod[TheAttr] -> method1 -> method2 -> TheMethod SUCCESS
Теперь, что я хочу, это:
somemethod -> method1[TheAttr] -> method2 -> TheMethod SUCCESS
и
somemethod -> method1 -> method2[TheAttr] -> TheMethod SUCCESS
Таким образом, другими словами, любой промежуточный вызывающий объект, имеющий украшение, должен приводить к допустимому использованию 'TheMethod'/вызовов "сквозь", допустимое использование также должно быть действительным.
Можно ли это проверить с помощью NDepend? Я экспериментировал с FillIterative, но пока безуспешно.
Спасибо, Тим
PS.: Вот моя текущая попытка:
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]
}