Уточнение правила 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
, Таким образом, мы должны были обеспечить произвольный порядок между этими двумя уровнями видимости.
Обратите также внимание на то, что метод / поле / вложенный тип может быть объявлен во вложенном типе (рекурсивном), поэтому для корректности нам необходимо собрать видимость всех внешних типов.
Эти два факта заставляют меня думать, что мы можем построить крайние случаи, когда ваше правило будет возвращать ложное срабатывание, но, немного повозившись, у меня ничего не получилось.
Мы советуем вам посмотреть на вашу кодовую базу (ы), как ведут себя ваши пользовательские правила, чтобы увидеть, должны ли они быть изменены. Если это хорошо, то считайте, что это хорошо, пока в конце концов не найдете ложный положительный результат.
В блоге Эрика Липперта ведутся долгие споры о том, должен ли член внутреннего типа быть объявленным публичным или внутренним. С обеих сторон имеются веские аргументы, и то, как написано наше правило кода, благоприятствует той стороне, которую оно должно быть объявлено как внутреннее, а ваше изменение - той стороне, которую оно должно быть объявлено как публичное.