Уточнение правила CQLinq для вложенной видимости

У нас есть NDepend 5.4.1, и мы хотим изменить запросы для поля / типа / метода, которые могли бы иметь меньшую видимость. Мы хотим, чтобы запрос учитывал область действия включающего класса при принятии решения, считать ли это нарушением.

Например,

internal class X
{
   public int A;
   public void B() { }
   public class C
   {
      // …
   }
}

Мы не хотим, чтобы A, B или C генерировали нарушение, говоря, что любое из них должно быть внутренним. С другой стороны, если класс X был общедоступным, и ни один из A, B и C не используется вне сборки, то все они должны вызывать нарушения.

Для этого я добавил следующую строку к запросам:

 // consider visibility of enclosing class
 f.ParentType.Visibility < f.OptimalVisibility

Так что для полей новый запрос выглядит так:

// <Name>Fields that could have a lower visibility</Name>
warnif count > 0 from f in JustMyCode.Fields where 
  f.Visibility != f.OptimalVisibility &&
 !f.HasAttribute("NDepend.Attributes.CannotDecreaseVisibilityAttribute".AllowNoMatch()) &&
 !f.HasAttribute("NDepend.Attributes.IsNotDeadCodeAttribute".AllowNoMatch()) &&
 // consider visibility of enclosing class
 f.ParentType.Visibility < f.OptimalVisibility

select new { f, 
             f.Visibility , 
             CouldBeDeclared = f.OptimalVisibility,
             f.MethodsUsingMe }

Я изменил запрос на видимость метода и видимость типа аналогичным образом, за исключением типов, которые я проверяю, есть ли родительский тип:

(t.ParentType == null || t.ParentType.Visibility < t.OptimalVisibility)

На первый взгляд и после запуска некоторых тестов, это, кажется, делает правильную вещь. Мой вопрос заключается в том, будет ли это генерировать какие-либо ложные срабатывания или пропускать какие-либо нарушения, так как я не уверен, что порядок перечисления (сравнения) в enum будет работать правильно во всех случаях.

1 ответ

Здесь NDepend.CodeModel.Visibility декларация перечисления:

   public enum Visibility {
      None = 0,
      Public = 1,
      ProtectedAndInternal = 2,
      ProtectedOrInternal = 3,
      Internal = 4,
      Protected = 5,
      Private = 6
   }

следовательно x.ParentType.Visibility < x.OptimalVisibility средства x parent type visibility is strictly less restrictive than x optimal visibility,

Заметить, что Protected приказано как более ограничительный, чем Internal который не true ни Internal является более ограничительным, чем Protected, Таким образом, мы должны были обеспечить произвольный порядок между этими двумя уровнями видимости.

Обратите также внимание на то, что метод / поле / вложенный тип может быть объявлен во вложенном типе (рекурсивном), поэтому для корректности нам необходимо собрать видимость всех внешних типов.

Эти два факта заставляют меня думать, что мы можем построить крайние случаи, когда ваше правило будет возвращать ложное срабатывание, но, немного повозившись, у меня ничего не получилось.

Мы советуем вам посмотреть на вашу кодовую базу (ы), как ведут себя ваши пользовательские правила, чтобы увидеть, должны ли они быть изменены. Если это хорошо, то считайте, что это хорошо, пока в конце концов не найдете ложный положительный результат.


В блоге Эрика Липперта ведутся долгие споры о том, должен ли член внутреннего типа быть объявленным публичным или внутренним. С обеих сторон имеются веские аргументы, и то, как написано наше правило кода, благоприятствует той стороне, которую оно должно быть объявлено как внутреннее, а ваше изменение - той стороне, которую оно должно быть объявлено как публичное.

Другие вопросы по тегам