PVS-Studio - это инструмент для выявления ошибок в исходном коде программ, написанных на языках С, C++ и C#.
PVS-Studio выполняет статический анализ кода и генерирует отчёт, помогающий программисту находить и устранять ошибки. PVS-Studio выполняет широкий спектр проверок кода, но наиболее силён в поисках опечаток и последствий неудачного Copy-Paste. Показательные примеры таких ошибок: V501, V517, V522, V523, V3001.
Анализатор ориентирован на разработчиков, использующих среду Visual Studio, и может в фоновом режиме выполнять анализ измененных файлов после их компиляции. В идеале ошибки будут обнаружены и исправлены ещё до попадания в репозиторий. Однако ничто не мешает использовать анализатор для проверки всего решения целиком или для встраивания в системы непрерывной интеграции. Эти и иные способы использования анализатора описаны в документации.
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, так как они предоставляют информацию об узле, а не об объекте. Пусть, например, мы анализируем следующий код:
Можно было бы попробовать пройтись вверх по дереву до объявления переменной, но это было бы слишком расточительно с точки зрения производительности и объема кода. К тому же, объявление запросто может находиться где-нибудь в другом файле, или даже в сторонней библиотеке, исходного кода которой у нас нет Тут на помощь и приходит семантическая модель. Можно выделить 3 наиболее часто используемые функции, предоставляемые семантической моделью:
На каждом из этих пунктов следует остановиться подробнее, так как все они важны и повсеместно применяются при статическом анализе кода. Получение информации об объекте. Symbol Информацию об объекте предоставляют так называемые символы (symbols). Базовый интерфейс символа – ISymbol, предоставляет методы и свойства, общие для всех объектов, независимо от того, чем они являются – полем, свойством или чем-то ещё. Существует ряд производных типов, выполняя приведение к которым можно получать более специфическую информацию об объекте. К таким интерфейсам относятся IFieldSymbol, IPropertySymbol, IMethodSymbol и прочие. Например, используя приведение к интерфейсу IFieldSymbol и обратившись к полю IsConst можно узнать, является ли узел константным полем. А если использовать интерфейс IMethodSymbol, можно узнать, возвращает-ли метод какое-либо значение. Для символов определено свойство Kind, возвращающее элементы перечисления SymbolKind. По своему предназначению это перечисление аналогично перечислению SyntaxKind. То есть с помощью свойства Kind можно узнать, с чем мы сейчас работаем – локальным объектом, полем, свойством, сборкой и пр. Пример использования. Узнаём, является ли узел константным полем. Предположим, что имеется определение поля следующего вида:
После проверки на null, используя свойство Kind, конкретизирующее символ, убеждаемся, что идентификатор на самом деле является полем. Если это действительно так – выполняем приведение к производному интерфейсу IFieldSymbol, который позволит обратиться к свойству IsConst, получив тем самым информацию о константности поля. Получение информации о типе объекта. Интерфейс ITypeSymbol Часто необходимо узнать тип объекта, представляемого узлом. Как я писал выше, оператор is и метод GetType не подходят, так как они оперируют с типом узла, а не анализируемого объекта. К счастью, выход есть, причём весьма элегантный. Нужную информацию можно получить, используя интерфейс ITypeSymbol. Для его получения используется метод GetTypeInfo объекта типа SemanticModel. Вообще этот метод возвращает структуру TypeInfo, содержащую 2 важных свойства:
Используя интерфейс ITypeSymbol, возвращаемый этими свойствами, можно получить всю интересующую информацию о типе. Эта информация извлекается за счёт обращения к свойствам, некоторые из которых приведены ниже:
Стоит отметить, что можно узнавать не только тип объекта, но и тип всего выражения целиком. Например, вы можете получить тип выражения a + b, и по отдельности типы переменных a и b. Так как эти типы могут отличаться, возможность получения типов для всего выражения целиком является достаточно полезной при разработке некоторых диагностических правил. Кроме того, как и для интерфейса ISymbol, существует ряд производных интерфейсов, позволяющих получить более специфическую информацию. Пример использования. Получение названий всех реализуемых типом интерфейсов Для того, чтобы получить названия всех интерфейсов, реализуемых типом, а также базовыми типами, можно использовать следующий код:
Получение константных значений Семантическую модель можно использовать также для получения константных значений. Эти значения можно получить для константных полей, символьных, строковых и числовых литералов. Выше было описано, как можно получить константные значения, используя лексемы. Семантическая модель предоставляет более удобный интерфейс для этого. В этом случае нам не нужны лексемы, достаточно иметь узел, из которого можно получить константное значение – остальное модель сделает самостоятельно. Это очень удобно, так как, напоминаю, при анализе основная работа ведётся именно с узлами. Для получения константных значений используется метод GetConstantValue, возвращающий структуру Optional<Object>, используя которую, легко проверить успешность операции и получить интересующее нас значение. Пример использования. Получение константного значения поля Предположим, что имеется анализируемый код:
Краткое обобщение Кратко обобщив информацию данного раздела, можно выделить следующие пункты, касаемо семантической модели:
Syntax visualizer Syntax visualizer (далее – визуализатор) – расширение для среды разработки Visual Studio, входящее в комплект Roslyn SDK (который можно загрузить в галерее Visual Studio). Данный инструмент, как следует из названия, выполняет функции отображения синтаксического дерева. Как видно из рисунка, синими элементами отображаются узлы, зелёными – лексемы, красными – дополнительная синтаксическая информация. Кроме этого для каждого узла можно узнать его тип, значение Kind, значения свойств. Кроме того есть возможность получения интерфейсов ISymbol и ITypeSymbolдля узлов дерева. Данный инструмент удобен при использовании методологии TDD, когда перед реализацией диагностического правила вы пишете набор юнит-тестов, а лишь затем приступаете к программированию логики правила. Визуализатор позволяет легче ориентироваться по написанному коду, узнать, на обход какого узла нужно подписаться и куда двигаться по дереву, для каких узлов необходимо (и можно) получить тип и символ, упрощая тем самым процесс разработки диагностического правила. Помимо представления дерева в формате, приведённом на рисунке выше, можно отобразить его в более наглядной форме. Для этого достаточно вызвать контекстное меню для интересующего вас элемента и выбрать пункт View Directed Syntax Graph. При помощи этого механизма я получал деревья различных синтаксических конструкций, используемых и приводимых ранее в статье. История из жизни. В ходе разработки PVS-Studio был случай, когда возникало исключение переполнения стека. Как оказалось, дело в том, что в одном из проверяемых проектов - ILSpy - есть автосгенерированный файл Parser.cs, в котором присутствует просто какое-то нереальное количество вложенных операторов if. В итоге, при попытке обхода дерева просто заканчивалась стековая память. В анализаторе мы эту проблему победили, просто увеличив максимальный размер стека для потоков, в которых происходит обход, но синтаксический визуализатор, заодно с Visual Studio, до сих пор "отваливается" на этом файле. Можете проверить сами. Откройте заветный файл, найдите эту "бездну" операторов if и попробуйте посмотреть синтаксическое дерево (например, строка 3218). Особенности, которые необходимо учитывать при разработке статического анализатора Существует ряд правил, которых необходимо придерживаться, разрабатывая статические анализаторы. Соблюдение этих правил позволит сделать более качественный продукт и реализовывать функциональные диагностические правила.
Алгоритм написания диагностических правил Поиск ошибок, осуществляемый статическим анализатором, реализуется за счёт различных диагностических правил. Для реализации всех правил существует набор общих действий, выделив которые, можно получить общий алгоритм написания диагностики.
Пример диагностического правила. Поиск пропущенного оператора throw В статическом анализаторе кода PVS-Studio есть диагностика V3006, которая ищет пропущенный оператор throw. Логика следующая – создаётся объект исключения, но при этом он никак не используется (ссылка на него никуда не передаётся, не возвращается из метода и т.п.). Тогда, скорее всего, можно сказать, что программист пропустил оператор throw. В итоге исключение не будет сгенерировано, а созданный объект просто будет уничтожен при следующей сборке мусора. Так как с правилом мы уже определились, можно начинать писать юнит-тесты. Пример позитивного теста:
Ниже будет приведена возможная реализация данного диагностического правила. Я специально несколько переписал и упростил код, чтобы сделать его короче и легче для понимания. Но даже такое небольшое правило справляется со своей задачей и находит реальные ошибки. Общий код поиска пропущенного оператора throw:
Кого-то может смутить тип SemanticModelAdapter. Ничего хитрого здесь нет, это обёртка над семантической моделью. В данном примере она используется для тех же целей, что и обыкновенная семантическая модель (объект типа SemanticModel). Метод проверки, является ли тип исключением:
Метод проверки, что ссылка никуда не передаётся и не сохраняется:
С первой, думаю, всё понятно – мы проверяем, что родительский узел – простое выражение. Вторая проверка тоже не таит в себе секретов. Если родительский узел – лямбда-выражение, проверим, что ссылка не возвращается из лямбды. Roslyn. Достоинства и недостатки Roslyn – не панацея. Несмотря на то, что это мощная платформа для разбора и анализа кода, как и у любого проекта, у него есть свои недостатки. В то же время достоинств у платформы тоже масса. Что ж, давайте выделим некоторые пункты из обеих категорий. Достоинства
Недостатки
PVS-Studio – статический анализатор кода, использующий Roslyn API PVS-Studio – это статический анализатор кода, предназначенный для выявления ошибок в исходном коде программ, написанных на C, C++, C#. Та часть анализатора, которая отвечает за проверку C# кода, написана с использованием Roslyn API. Знания и правила, изложенные выше, не взяты с потолка – они получены и сформулированы в ходе работы над анализатором. PVS-Studio является примером того, какой продукт можно создать, используя Roslyn. В данный момент в анализаторе реализовано свыше 80 диагностических правил. PVS-Studio уже нашёл ошибки во множестве проектов. Некоторые из них:
У некоторых может возникнуть вопрос: "А что же интересного удалось найти в ходе проверки проектов?". Много чего интересного! Если кто-то думает, что профессионалы не допускают ошибок, рекомендую ознакомиться с базой ошибок, найденных в open source проектах. Помимо этого в блоге можно почитать статьи о проверке тех или иных проектов. Итоги Общее
Синтаксическое дерево
Семантическая модель
Статический анализ
Заключение Подводя итог, хотелось бы сказать, что Roslyn - это действительно мощная платформа, на основе которой можно создавать различные многофункциональные инструменты – анализаторы, инструменты рефакторинга и много чего ещё. Низкий поклон Microsoft за Roslyn, а также за возможность его свободного использования. Однако наличия платформы мало – нужно знать, как с ней работать. Основные понятия и принципы работы и были описанные в данной статье. Полученные знания помогут вам легче и быстрее вникнуть в процесс разработки с использованием Roslyn API, было бы желание. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии


