Автор: Sergey Teplyakov
У меня уже давно чесались руки сделать анализатор, который поможет отлавливать разные ошибки, в той или иной степени, специфичные для платформы .NET. Многие подобные ошибки уже прекрасно отлавливает R#, но ведь всегда хочется чего-то своего. К тому же, анализаторы Розлина бесшовно интегрируются в билд процесс, могут использоваться по ночам (*), да и могут содержать рулы, специфичные для вашего продукта.
Итак, взяв за основу идеи из R# и из аналогичной библиотеки для Java от гугла под названием Error Prone, я взялся за работу. Ниже представлен первая часть результатов моей работы.
Вызов чистых методов
Отсутствие наблюдение результатов вызова чистого метода является одной из наиболее частых ошибок, которые возникают во время локального тестирования. Проблема в том, что просто читая код, очень сложно сказать заранее, является ли вызов someCollection.Union(anotherCollection) чистым и возвращает новую коллекцию, или же меняет исходную.
Вот примеры работы этого правила:
Это правило учитывает ряд известных типов из BCL, которые гарантированно являются неизменяемыми или содержат только чистые методы. Оно также учитывает атрибут PureAttribute, которым вы можете пометить любые методы. Я также добавил пару эвристик: все типы с приставкой Immutable считаются неизменяемыми, все методы с приставкой With, который возвращают тип первого аргумента, а также все методы расширения неизменяемых типов является чистыми. У правила бывают ложные срабатывания, но их не так и много, а пользы - достаточно.
К сожалению, пока не понятно, как использовать существующие аннотации чистоты из библиотеки Code Contracts и нужно подумать, как сделать решение более расширяемым. Но даже сейчас правило нашло десяток мелких ошибок в коде моего проекта (все они были в тестах и во второстепенном коде, но все же).
Создание объектов без сохранения значения
Частным случаем предыдущего правила, является правило, которое ищет вызовы конструкторов объектов, без использования полученного результата, вида new SomeObject(),
К сожалению, выдавать предупреждения на любой стоящий особняком вызов new нельзя, поскольку люди часто делают страшные вещи, в виде каких-то операций с побочными эффектами в конструкторах. Но в некоторых случаях, можно точно сказать, что никаких побочных эффектов у конструктора нет. Это относится к вызовам конструкторов по умолчанию значимых типов, коллекций, примитивных объектов или неизменяемых типов.
Особняком стоит частный случай этого правила, которое выдает ошибку при создании объекта исключения:
Форматирование строк
Еще один популярный вид ошибок это неправильные аргументы при вызове string.Format и подобных методов. Да, частота использования string.Format заметно упала при появлении интерполяции строк в C# 6.0, но легаси кода много, да и в других местах форматные строки используются часто.
ErrorProne.NET содержит три правила:
-
Неизвестные аргументы в строке формата
-
Лишние аргументы, которые не используются в строке формата
-
Невалидная строка формата
(Да, вторая проблема не проявляется во время исполнения и не ведет к генерации исключения FormatException, но, ИМХО, это может лишь скрыть ошибки, да и проявляться на практике может даже чаще, чем другие варианты. Именно это правило позволило найти явный баг в коде Ролзина. Вот тикет, кому интересно).
Неизвестные аргументы:
Лишние аргументы:
Невалидная форматная строка:
И есть еще отдельное правило, валидирующее паттерн регулярного выражения:
Обратите внимание, что правило учитывает атрибут JetBrains.Annotations.StringFormatMethodAttribute, который можно получить через NuGet, или же просто создать такой атрибут в вашем собственном коде (используется такая себе утиная типизация).
-----------------
(*) Да, я знаю о существовании ReSharper Command Line Tools
Заключение
Я прекрасно осознаю, что подобных инструментов на рынке довольно много, конкурировать с R#, или анализаторами от PVS-Studio сложно, да и цели такой нет. Просто задача эта довольно интересная и хочется собрать в одном месте ценные анализаторы, которую будут полезны здесь и сейчас в моих личных проектах, и проектах моих коллег.
Да, и здесь рассмотрена лишь часть правил, поддерживаемых ErrorProne.NET, так что ждите продолжение в следующей части,)
Ссылки
-
ErrorProne.NET on GitHub
-
SolutionDiagnosticRunner on GitHub именно его я использую для запуска анализаторов из командной строки для анализа разных проектов, включая проект Roslyn
-
ErrorProne.NET on Visual Studio Gallery
-
ErrorProne.NET on NuGet.org
З. Ы. Если есть идеи рулов, которые могли бы существенно облегчить вам жизнь и сделать ваш код чище/проще/понятней пишите, обсудим!