Форум программистов, компьютерный форум, киберфорум
el_programmer
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
PVS-Studio - это инструмент для выявления ошибок в исходном коде программ, написанных на языках С, C++ и C#.

PVS-Studio выполняет статический анализ кода и генерирует отчёт, помогающий программисту находить и устранять ошибки. PVS-Studio выполняет широкий спектр проверок кода, но наиболее силён в поисках опечаток и последствий неудачного Copy-Paste. Показательные примеры таких ошибок: V501, V517, V522, V523, V3001.

Анализатор ориентирован на разработчиков, использующих среду Visual Studio, и может в фоновом режиме выполнять анализ измененных файлов после их компиляции. В идеале ошибки будут обнаружены и исправлены ещё до попадания в репозиторий. Однако ничто не мешает использовать анализатор для проверки всего решения целиком или для встраивания в системы непрерывной интеграции. Эти и иные способы использования анализатора описаны в документации.

Введение в Roslyn. Использование для разработки инструментов статического анализа. Часть 2

Запись от el_programmer размещена 19.05.2016 в 17:27
Показов 3784 Комментарии 0

Часть 1: https://www.cyberforum.ru/blog... g4266.html


Семантическая модель

Семантическая модель предоставляет информацию об объектах и о типах объектов. Это очень мощный инструмент, позволяющий проводить глубокий и сложный анализ. Именно поэтому важно иметь корректную компиляцию и корректную семантическую модель. Напомню, что для этого проект должен быть скомпилированным.

Следует помнить, что при анализе мы работаем с узлами, а не с объектами. Поэтому для получения информации, например, о типе объекта не сработают ни оператор is, ни метод GetType, так как они предоставляют информацию об узле, а не об объекте. Пусть, например, мы анализируем следующий код:

C#
1
a = 3;
О том, что такое a, из этого кода можно лишь строить предположения. Нельзя сказать, локальная ли это переменная, или свойство, или поле, можно сделать только приблизительные предположения о типе. Но догадки никого не интересуют, нужна точная информация.

Можно было бы попробовать пройтись вверх по дереву до объявления переменной, но это было бы слишком расточительно с точки зрения производительности и объема кода. К тому же, объявление запросто может находиться где-нибудь в другом файле, или даже в сторонней библиотеке, исходного кода которой у нас нет

Тут на помощь и приходит семантическая модель.

Нажмите на изображение для увеличения
Название: image11.png
Просмотров: 731
Размер:	24.6 Кб
ID:	3839

Можно выделить 3 наиболее часто используемые функции, предоставляемые семантической моделью:
  • Получение информации об объекте;
  • Получение информации о типе объекта;
  • Получение константных значений.

На каждом из этих пунктов следует остановиться подробнее, так как все они важны и повсеместно применяются при статическом анализе кода.


Получение информации об объекте. Symbol

Информацию об объекте предоставляют так называемые символы (symbols).

Базовый интерфейс символа – ISymbol, предоставляет методы и свойства, общие для всех объектов, независимо от того, чем они являются – полем, свойством или чем-то ещё.

Существует ряд производных типов, выполняя приведение к которым можно получать более специфическую информацию об объекте. К таким интерфейсам относятся IFieldSymbol, IPropertySymbol, IMethodSymbol и прочие.

Например, используя приведение к интерфейсу IFieldSymbol и обратившись к полю IsConst можно узнать, является ли узел константным полем. А если использовать интерфейс IMethodSymbol, можно узнать, возвращает-ли метод какое-либо значение.

Для символов определено свойство Kind, возвращающее элементы перечисления SymbolKind. По своему предназначению это перечисление аналогично перечислению SyntaxKind. То есть с помощью свойства Kind можно узнать, с чем мы сейчас работаем – локальным объектом, полем, свойством, сборкой и пр.


Пример использования. Узнаём, является ли узел константным полем.

Предположим, что имеется определение поля следующего вида:

C#
1
private const Int32 a = 10;
А где-то ниже – следующий код:

C#
1
var b = a;
Предположим, что нам требуется узнать, является ли a константным полем. Из вышеприведённого выражения можно получить необходимую информацию об узле а, используя семантическую модель. Код получения необходимой информации выглядит следующий образом:

C#
1
2
3
4
5
6
7
8
9
Boolean? IsConstField(SemanticModel model,        
                      IdentifierNameSyntax identifier)
{
  ISymbol smb = model.GetSymbolInfo(identifier).Symbol;
  if (smb == null)
    return null;
  return smb.Kind == SymbolKind.Field && 
         (smb as IFieldSymbol).IsConst;
}
Сначала получаем символ для идентификатора, используя метод GetSymbolInfo объекта типа SemanticModel, после чего сразу обращаемся к полю Symbol (именно оно содержит интересующую нас информацию, поэтому в данном случае нет смысла хранить где-то структуру SymbolInfo, возвращаемую методом GetSymbolInfo).

После проверки на null, используя свойство Kind, конкретизирующее символ, убеждаемся, что идентификатор на самом деле является полем. Если это действительно так – выполняем приведение к производному интерфейсу IFieldSymbol, который позволит обратиться к свойству IsConst, получив тем самым информацию о константности поля.


Получение информации о типе объекта. Интерфейс ITypeSymbol

Часто необходимо узнать тип объекта, представляемого узлом. Как я писал выше, оператор is и метод GetType не подходят, так как они оперируют с типом узла, а не анализируемого объекта.

К счастью, выход есть, причём весьма элегантный. Нужную информацию можно получить, используя интерфейс ITypeSymbol. Для его получения используется метод GetTypeInfo объекта типа SemanticModel. Вообще этот метод возвращает структуру TypeInfo, содержащую 2 важных свойства:
  • ConvertedType – возвращает информацию о типе выражения после выполнения неявного приведения. Если приведения не было, возвращаемое значение аналогично тому, что возвращает свойство Type;
  • Type – возвращает тип выражения, представленного в узле. Если получить тип выражения невозможно, возвращается значение null.Если тип не может быть определён из-за какой-то ошибки, возвращается интерфейс IErrorTypeSymbol.

Используя интерфейс ITypeSymbol, возвращаемый этими свойствами, можно получить всю интересующую информацию о типе. Эта информация извлекается за счёт обращения к свойствам, некоторые из которых приведены ниже:
  • AllInterfaces – список всех реализуемых типом интерфейсов. Учитываются также и интерфейсы, реализуемые базовыми типами;
  • BaseType – базовый тип;
  • Interfaces – список интерфейсов, реализуемых конкретно данным типом;
  • IsAnonymousType – информация о том, является ли тип анонимным;
  • IsReferenceType – информация о том, является ли тип ссылочным;
  • IsValueType – информация о том, является ли тип значимым;
  • TypeKind – конкретизирует тип (аналогично свойству Kind для интерфейса ISymbol). Содержит информацию о том, что из себя представляет тип – класс, структуру, перечисление и т.д.

Стоит отметить, что можно узнавать не только тип объекта, но и тип всего выражения целиком. Например, вы можете получить тип выражения a + b, и по отдельности типы переменных a и b. Так как эти типы могут отличаться, возможность получения типов для всего выражения целиком является достаточно полезной при разработке некоторых диагностических правил.

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


Пример использования. Получение названий всех реализуемых типом интерфейсов

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

C#
1
2
3
4
5
6
7
8
9
10
List<String> GetInterfacesNames(SemanticModel model, 
                                IdentifierNameSyntax identifier)
{
  ITypeSymbol nodeType = model.GetTypeInfo(identifier).Type;
  if (nodeType == null)
    return null;
  return nodeType.AllInterfaces
                 .Select(p => p.Name)
                 .ToList();
}
Всё достаточно просто, используемые здесь методы и свойства были описаны выше, поэтому никаких трудностей с пониманием данного кода, думаю, возникнуть не должно.


Получение константных значений

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

Для получения константных значений используется метод GetConstantValue, возвращающий структуру Optional<Object>, используя которую, легко проверить успешность операции и получить интересующее нас значение.


Пример использования. Получение константного значения поля

Предположим, что имеется анализируемый код:

C#
1
private const String str = "Some string";
Если где-то в коде программы встретится объект str, используя семантическую модель можно будет легко получить строку, на которую ссылается это поле:

C#
1
2
3
4
5
6
7
8
String GetConstStrField(SemanticModel model, 
                        IdentifierNameSyntax identifier)
{
  Optional<Object> optObj = model.GetConstantValue(identifier);
  if (!optObj.HasValue)
    return null;
  return optObj.Value as String;
}

Краткое обобщение

Кратко обобщив информацию данного раздела, можно выделить следующие пункты, касаемо семантической модели:
  • Семантическая модель предоставляет семантическую информацию (об объектах, их типах и пр.);
  • Необходима для проведения глубокого и сложного анализа;
  • Для получения корректной семантической модели проект должен быть скомпилированным;
  • Семантическую информацию об объекте предоставляет интерфейс ISymbol;
  • Семантическую информацию о типе объекта предоставляет интерфейс ITypeSymbol;
  • С помощью семантической модели возможно получение значений константных полей и литералов.


Syntax visualizer

Syntax visualizer (далее – визуализатор) – расширение для среды разработки Visual Studio, входящее в комплект Roslyn SDK (который можно загрузить в галерее Visual Studio). Данный инструмент, как следует из названия, выполняет функции отображения синтаксического дерева.


Нажмите на изображение для увеличения
Название: image12.png
Просмотров: 827
Размер:	46.7 Кб
ID:	3840

Как видно из рисунка, синими элементами отображаются узлы, зелёными – лексемы, красными – дополнительная синтаксическая информация. Кроме этого для каждого узла можно узнать его тип, значение Kind, значения свойств. Кроме того есть возможность получения интерфейсов ISymbol и ITypeSymbolдля узлов дерева.

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

Помимо представления дерева в формате, приведённом на рисунке выше, можно отобразить его в более наглядной форме. Для этого достаточно вызвать контекстное меню для интересующего вас элемента и выбрать пункт View Directed Syntax Graph. При помощи этого механизма я получал деревья различных синтаксических конструкций, используемых и приводимых ранее в статье.


Нажмите на изображение для увеличения
Название: image13.png
Просмотров: 727
Размер:	7.4 Кб
ID:	3841

История из жизни.

В ходе разработки PVS-Studio был случай, когда возникало исключение переполнения стека. Как оказалось, дело в том, что в одном из проверяемых проектов - ILSpy - есть автосгенерированный файл Parser.cs, в котором присутствует просто какое-то нереальное количество вложенных операторов if. В итоге, при попытке обхода дерева просто заканчивалась стековая память. В анализаторе мы эту проблему победили, просто увеличив максимальный размер стека для потоков, в которых происходит обход, но синтаксический визуализатор, заодно с Visual Studio, до сих пор "отваливается" на этом файле.

Можете проверить сами. Откройте заветный файл, найдите эту "бездну" операторов if и попробуйте посмотреть синтаксическое дерево (например, строка 3218).


Особенности, которые необходимо учитывать при разработке статического анализатора

Существует ряд правил, которых необходимо придерживаться, разрабатывая статические анализаторы. Соблюдение этих правил позволит сделать более качественный продукт и реализовывать функциональные диагностические правила.
  1. Для глубокого и качественного анализа нужна полная информация о всех типах, встретившихся в коде. В большинстве диагностических правил недостаточно простого обхода узлов дерева, часто приходится обрабатывать типы выражений и получать информацию об анализируемых объектах. Для этого и нужна семантическая модель, которая должна быть корректной. Напомню, что для этого проект должен быть скомпилированным, все зависимости должны быть на месте. Тем не менее, даже если это так, не стоит пренебрегать различными проверками результатов, получаемых с использованием семантической модели;
  2. Важно правильно выбирать тип узла для начала анализа. Это позволит уменьшить количество перемещений по дереву и различных приведений. Естественно, это также уменьшит объем кода, упростив его поддержку. Для того, чтобы лучше определиться со стартовым узлом анализа, используйте синтаксический визуализатор;
  3. Если нет уверенности в том, что код является ошибочным, лучше не ругаться. Но в пределах разумного, конечно. Дело в том, что если анализатор будет ругаться по делу и без дела, появится слишком большое количество шума в виде ложных срабатываний, на фоне которых реальные ошибки найти будет трудно. С другой стороны, если совсем ни на что не ругаться, толку от анализатора тоже не будет. Поэтому иногда приходится выбирать компромисс, но конечная цель – свести количество ложных срабатываний к минимуму, в идеале – к 0;
  4. При разработке диагностических правил важно предусмотреть все возможные, невозможные, а также ряд невероятных случаев, с которыми вы можете столкнуться в ходе анализа. Для этого необходимо разрабатывать большое количество юнит-тестов, как позитивных – фрагментов кода, где должна срабатывать ваша диагностика, так и негативных – тех фрагментов, на которые не стоит выдавать предупреждения;
  5. В процесс разработки диагностических правил отлично вписывается методология TDD. Изначально разрабатываются наборы позитивных и негативных юнит-тестов, и лишь после этого начинается реализация диагностического правила. Это позволит легче ориентироваться с синтаксическим деревом по мере реализации, так как перед глазами уже будут примеры различных деревьев. К тому же на этом этапе пригодится синтаксический визуализатор;
  6. Важно тестировать анализатор на реальных проектах. Как бы вы ни старались, скорее всего не удастся покрыть юнит-тестами все случаи, с которыми придётся столкнуться диагностическим правилам анализатора. Проверка же анализатора на реальных проектах позволит выявить места, где правила отрабатывают некорректно, следить за изменениями работы анализатора, увеличивать базу юнит-тестов.


Алгоритм написания диагностических правил

Поиск ошибок, осуществляемый статическим анализатором, реализуется за счёт различных диагностических правил. Для реализации всех правил существует набор общих действий, выделив которые, можно получить общий алгоритм написания диагностики.


Нажмите на изображение для увеличения
Название: image14.png
Просмотров: 828
Размер:	21.7 Кб
ID:	3842
  1. Первым шагом необходимо сформулировать суть правила. Перед разработкой необходимо обдумать, на какие же фрагменты кода стоит выдавать предупреждения, а на какие – нет;
  2. Когда диагностическое правило уже обрело некоторую форму и стало понятно, на какие ситуации стоит выдавать предупреждение, необходимо заняться разработкой юнит-тестов, а именно – реализовать наборы позитивных и негативных тестов. На позитивных тестах должна срабатывать ваша диагностика. На начальных этапах разработки важно сделать базу позитивных юнит тестов как можно больше, так как это позволит отлавливать больше подозрительных ситуаций. Не меньшее внимание стоит уделить и негативным юнит тестам. По мере разработки и тестирования диагностики, база негативных юнит-тестов будет постоянно пополняться. Именно за счёт этого будет снижаться количество ложных срабатываний, выводя соотношение хороших срабатываний к плохим в нужную сторону;
  3. После того, как разработан базовый набор юнит-тестов, можно приступать к реализации диагностики. Не забывайте пользоваться синтаксическим визуализатором – этот инструмент может сильно помочь в процессе программирования;
  4. После того, как диагностика будет готова, а все юнит-тесты будут успешно проходить, необходимо приступать к следующему этапу – тестированию на реальных проектах. Это позволит обнаружить ложные срабатывания (а может и падения) вышей диагностики, расширить базу юнит-тестов. Чем больше открытых проектов используется для тестирования, тем больше возможных вариантов анализируемого кода вы рассматриваете, тем лучше и мощнее становится ваша диагностика;
  5. После тестирования на реальных проектах скорее всего придётся дорабатывать диагностику, так как сходу редко можно попасть прямо в яблочко. Что ж, ничего страшного, это нормальный процесс! Вносите необходимые изменения и снова тестируйте правило;
  6. Повторяйте предыдущий пункт до тех пор, пока диагностика не покажет желаемый результат. После этого можно гордиться проделанной работой.


Пример диагностического правила. Поиск пропущенного оператора throw


Нажмите на изображение для увеличения
Название: image15.png
Просмотров: 870
Размер:	85.7 Кб
ID:	3843

В статическом анализаторе кода PVS-Studio есть диагностика V3006, которая ищет пропущенный оператор throw. Логика следующая – создаётся объект исключения, но при этом он никак не используется (ссылка на него никуда не передаётся, не возвращается из метода и т.п.). Тогда, скорее всего, можно сказать, что программист пропустил оператор throw. В итоге исключение не будет сгенерировано, а созданный объект просто будет уничтожен при следующей сборке мусора.

Так как с правилом мы уже определились, можно начинать писать юнит-тесты.

Пример позитивного теста:

C#
1
2
if (cond)
  new ArgumentOutOfRangeException();
Пример негативного теста:

C#
1
2
if (cond)
  throw new FieldAccessException();
Можно выделить следующие пункты в алгоритме работы диагностики:
  1. Подписываемся на обход узлов типа ObjectCreationExpressionSyntax. Этот тип узлов соответствует созданию объекта с использованием оператора new – как раз то, что нам нужно;
  2. Убеждаемся, что тип создаваемого объекта является совместимым с System.Exception (т.е. либо этим типом, либо производным). Если это так, будем считать, что тип является типом исключения. Для получения типа будем использовать семантическую модель (напоминаю, что модель предоставляет возможность получать тип выражения);
  3. Проверяем, что объект не используется (ссылка на объект никуда не записывается и не передаётся);
  4. Если предыдущие пункты соблюдены – выдаём предупреждение.

Ниже будет приведена возможная реализация данного диагностического правила. Я специально несколько переписал и упростил код, чтобы сделать его короче и легче для понимания. Но даже такое небольшое правило справляется со своей задачей и находит реальные ошибки.

Общий код поиска пропущенного оператора throw:

C#
1
2
3
4
5
6
7
8
9
10
11
12
readonly String ExceptionTypeName = typeof(Exception).FullName;
Boolean IsMissingThrowOperator(SemanticModelAdapter model,        
                               ObjectCreationExpressionSyntax node)
{           
  if (!IsExceptionType(model, node))
    return false;
 
  if (IsReferenceUsed(model, node.Parent))
    return false;
 
  return true; 
}
Как видно из кода, здесь выполняются действия, описанные в алгоритме, приведённом выше. В первом условии выполняется проверка того, что тип создаваемого объекта – тип исключения. Вторая проверка используется для определения, используется ли созданный объект.

Кого-то может смутить тип SemanticModelAdapter. Ничего хитрого здесь нет, это обёртка над семантической моделью. В данном примере она используется для тех же целей, что и обыкновенная семантическая модель (объект типа SemanticModel).

Метод проверки, является ли тип исключением:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
Boolean IsExceptionType(SemanticModelAdapter model,
                        SyntaxNode node)
{
  ITypeSymbol nodeType = model.GetTypeInfo(node).Type;
 
  while (nodeType != null && !(Equals(nodeType.FullName(),
                                      ExceptionTypeName)))
    nodeType = nodeType.BaseType;
 
  return Equals(nodeType?.FullName(),
                ExceptionTypeName);
 
}
Логика проста – получаем информацию о типе, проверяем всю иерархию наследования. Если в итоге обнаруживается, что один из базовых типов – System.Exception, считаем, что тип создаваемого объекта – тип исключения.

Метод проверки, что ссылка никуда не передаётся и не сохраняется:

C#
1
2
3
4
5
6
7
8
9
10
11
12
Boolean IsReferenceUsed(SemanticModelAdapter model, 
                     SyntaxNode parentNode)
{
  if (parentNode.IsKind(SyntaxKind.ExpressionStatement))
    return false;
 
  if (parentNode is LambdaExpressionSyntax)
    return (model.GetSymbol(parentNode) as IMethodSymbol)
             ?.ReturnsVoid == false;
 
  return true;
}
Можно было бы проверить, используется ли ссылка, но пришлось бы рассматривать слишком много случаев: возвращение из метода, передачу в метод, запись в переменную и т.п. Гораздо проще рассмотреть случаи, когда ссылка никуда не передаётся и не записывается. Это покрывается описанными выше проверками.

С первой, думаю, всё понятно – мы проверяем, что родительский узел – простое выражение. Вторая проверка тоже не таит в себе секретов. Если родительский узел – лямбда-выражение, проверим, что ссылка не возвращается из лямбды.


Roslyn. Достоинства и недостатки

Roslyn – не панацея. Несмотря на то, что это мощная платформа для разбора и анализа кода, как и у любого проекта, у него есть свои недостатки. В то же время достоинств у платформы тоже масса. Что ж, давайте выделим некоторые пункты из обеих категорий.


Достоинства
  • Множество типов узлов. Это может напугать на начальных стадиях работы с платформой, но на деле оказывается её большим достоинством. Можно подписаться на обход определённых узлов, соответствующих тем или иным конструкциям языка, тем самым анализируя интересующие нас участки. Кроме того, каждый тип узла предлагает характерный для него набор свойств, облегчая задачу получения необходимых данных;
  • Удобная навигация по дереву. Для перемещения по дереву или получения необходимых данных достаточно просто обращаться к свойствам узлов. Как сказано выше, каждый тип узла содержит свой набор свойств, что ещё больше упрощает задачу;
  • Семантическая модель. Сущность, позволяющая получать информацию об объектах и типах, предоставляя к тому же удобный интерфейс для этого, является очень сильной стороной платформы;
  • Открытый исходный код. Можно следить за процессом развития платформы, при желании посмотреть, что и как устроено. К тому же можно приобщиться к процессу разработки, сообщая разработчикам о найденных ошибках – это пойдёт на пользу всем.


Недостатки
  • Открытие проектов может порождать различные проблемы. Порой Roslyn не может корректно открыть проект (не подцепляет какую-нибудь зависимость, файл и т.п.), из-за чего не удаётся получить корректную компиляцию и, как итог – семантическую модель. Это рубит на корню глубокий анализ, так как без семантической модели глубокий анализ невозможен. Приходится использовать дополнительные средства (например, MSBuild) для корректного разбора решений/проектов;
  • Приходится изобретать собственные механизмы для, казалось бы, простых вещей. Например – сравнение узлов. Метод Equals для узлов просто сравнивает ссылки, чего явно недостаточно. Приходится изобретать свои механизмы сравнения.
  • Программа, построенная на базе Roslyn, может потреблять много памяти (гигабайты). Для современных 64-битных компьютеров с большим объемом памяти это не является критичным, но учитывать эту особенность стоит. Вполне возможно, что разработанный вами продукт будет бесполезен на слабых устаревших компьютерах.


PVS-Studio – статический анализатор кода, использующий Roslyn API

PVS-Studio – это статический анализатор кода, предназначенный для выявления ошибок в исходном коде программ, написанных на C, C++, C#.

Название: image17.jpg
Просмотров: 635

Размер: 168.4 Кб

Та часть анализатора, которая отвечает за проверку C# кода, написана с использованием Roslyn API. Знания и правила, изложенные выше, не взяты с потолка – они получены и сформулированы в ходе работы над анализатором.

PVS-Studio является примером того, какой продукт можно создать, используя Roslyn. В данный момент в анализаторе реализовано свыше 80 диагностических правил. PVS-Studio уже нашёл ошибки во множестве проектов. Некоторые из них:
  • Roslyn;
  • MSBuild;
  • CoreFX;
  • SharpDevelop;
  • MonoDevelop;
  • Microsoft Code Contracts;
  • NHibernate;
  • Space engineers;
  • И многие другие.

У некоторых может возникнуть вопрос: "А что же интересного удалось найти в ходе проверки проектов?". Много чего интересного! Если кто-то думает, что профессионалы не допускают ошибок, рекомендую ознакомиться с базой ошибок, найденных в open source проектах. Помимо этого в блоге можно почитать статьи о проверке тех или иных проектов.


Итоги


Общее
  • Roslyn позволяет разбирать и анализировать код до мельчайших подробностей. Это открывает простор для создания различных приложений на его основе, в том числе статических анализаторов;
  • Для серьёзного анализа проект должен быть скомпилированным, так как это обязательное условие для получения корректной семантической модели;
  • 2 сущности, на которых базируется статический анализ– синтаксическое дерево и семантическая информация. Только используя их в совокупности, можно проводить действительно серьёзный анализ;
  • Открытый исходный код – загружайте и пользуйтесь;
  • Syntax visualizer – полезное расширение, которое поможет вам при работе с платформой.


Синтаксическое дерево
  • Строится для каждого файла и является неизменяемым.
  • Состоит из 3-ёх основных элементов – syntax nodes, syntax tokens, syntax trivia;
  • Узлы – основной элемент дерева, с которым приходится работать в ходе анализа кода;
  • Для каждой конструкции узла определён узел своего типа, что позволяет легко получить необходимые данные, обращаясь к свойствам объекта узла;
  • Лексемы – терминалы грамматики языка, представляющие идентификаторы, ключевые слова, разделители и пр.;
  • Дополнительная синтаксическая информация – комментарии, пробельные символы, директивы препроцессора и пр.;
  • Используйте метод IsKind и перечисление SyntaxKind для конкретизации типа элемента дерева.


Семантическая модель
  • Для качественного анализа должна быть корректной;
  • Позволяет получать информацию об объектах и их типах;
  • Используйте метод GetSymbolInfo, интерфейс ISymbol и производные от него для получения информации о самом объекте;
  • Используйте метод GetTypeInfo, интерфейс ITypeSymbol и производные от него для получения информации о типе объекта или выражения;
  • Используйте метод GetConstantValue для получения константных значений.


Статический анализ
  • Если нет уверенности в том, что код ошибочен, лучше не ругаться. Не стоит засорять результат работы анализатора ложными срабатываниями;
  • При написании диагностик можно выделить общий алгоритм, соблюдение которого позволит реализовывать мощные и функциональные диагностические правила;
  • Используйте синтаксический визуализатор;
  • Чем больше юнит-тестов, тем лучше;
  • При разработке диагностических правил важно проверять их на различных реальных проектах.


Заключение


Нажмите на изображение для увеличения
Название: image18.png
Просмотров: 765
Размер:	155.4 Кб
ID:	3845

Подводя итог, хотелось бы сказать, что Roslyn - это действительно мощная платформа, на основе которой можно создавать различные многофункциональные инструменты – анализаторы, инструменты рефакторинга и много чего ещё. Низкий поклон Microsoft за Roslyn, а также за возможность его свободного использования.

Однако наличия платформы мало – нужно знать, как с ней работать. Основные понятия и принципы работы и были описанные в данной статье. Полученные знания помогут вам легче и быстрее вникнуть в процесс разработки с использованием Roslyn API, было бы желание.
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
Как ИИ начал спорить и врать (возможно почуяв опасность для себя от индустрии - уход от электроники).
Hrethgir 04.08.2026
Недельный диалог, на фоне событий с НПЗ. Да, из спирта можно получать бензин, и это не сложно. Но потом в схеме я решил избавиться от насоса, при этом полностью сделав контроль подачи спирта в. . .
Термопринтер QR701
Argus19 03.08.2026
Термопринтер QR701 Купил два термопринтера QR701. На сэлф-тесте написано: Language: PC936 (GB18030). Что означает, что принтеры могут печатать только латиницу и китайские иероглифы. Так же. . .
Создание формы заимствованного документа
Maks 03.08.2026
Задача: Необходимо создать собственную форму заимствованного документа. На форме должен быть реквизит "Покупатель", а также табличная часть со следующими реквизитами: - Расчетный счет покупателя. . .
Задача предоставления скидок покупателям
Maks 03.08.2026
Задача: В документе "Продажи" необходимо реализовать функционал предоставления скидок покупателям. Скидка должна автоматически рассчитываться и подставляться в соответствующее поле при выборе. . .
Почему SEO не начинается с ключевых слов: что проверить до написания текстов
Neotwalker 01.08.2026
Когда владельцу сайта предлагают заняться SEO, первым шагом часто становится сбор запросов и написание текстов. Логика кажется понятной: 1. Находим ключевые слова. 2. Добавляем их на. . .
Знание — сила: Доктрина интенциональности знаний, углубление в формулу
Hrethgir 01.08.2026
https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11957&stc=1&d=1785567302 Знаменитый афоризм Фрэнсиса Бэкона «Знание — сила» (Scientia potentia est) в массовой культуре принято понимать. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru