Есть два вида поиска, которые вы часто используете: «Find Text» и «Find Usages». Но ни один из них не позволяет искать сложные языковые конструкции, например, все места в вашем коде, где используется выражение "
В ReSharper 5.0 появился новый тип поиска «Search With Pattern», который позволяет искать куски кода по шаблону, причем на части этого шаблона можно накладывать ограничения. Например, для выражений можно указать тип, а для аргументов их предполагаемое количество.
Давайте рассмотрим конкретный пример. Будем искать в вашем коде все выражения "
Откройте окно «Search With Pattern» (Resharper -> Find -> Search With Pattern) и введите в текстовое поле следующий шаблон:
Строка
Буквально за несколько секунд, без знаний о регулярных выражениях мы создали шаблон для поиска. Но есть еще одна приятная и очень мощная вещь: обратите внимание, что под полем редактирования шаблона есть галочка «Match similar constructs». Если эта галочка установлена, то происходит поиск не только точных совпадений с образцом, но и сематически идентичных конструкций. Например, конструкции "
Все готово! Теперь можете нажать кнопку «Find» и посмотреть на результаты.
Такой мощный поиск без функции замены был бы не полным, ведь интересно не просто найти все нехорошие места в программе, но и заменить их правильным кодом. Для этого в окне «Search With Pattern» нажмите кнопку «Replace». Появится поле для ввода паттерна замены. В этом поле можно написать любой корректный с точки зрения языка текст, также можно использовать плейсхолдеры. Введите в это поле:
Теперь нажимайте кнопку Replace!
Теперь у вас есть шаблон для поиска и шаблон для замены. Логично сделать из этого подсветку и QuickFix. Для этого в окне редактирования паттерна просто нажмите кнопу «Save». Ваш паттерн сохранится в «Patterns Catalogue». Этот каталог можно просто использовать для хранения часто используемых шаблонов, а можно сделать из него мощное средство для создания собственных анализов.
Если вы откроете каталог (ReSharper -> Tools -> Patterns Catalogue), то сможете для своего паттерна настроить настроить текст подсказки, текст, который будет показываться в QuickFix и тип подсветки. Установите для своего паттерна все эти параметры.
Все! Подсветка работает! Теперь весь код, соответствующий вашему шаблону, будет подсвечиваться налету! А на подсветке будет появляться соответствующий QuickFix!
Паттерн поиска, который упрощает выражения:
В этом примере мы использовали плейсхолдеры для типа, выражения и идентификатора. При этом не задали никаких ограничений на них, но зато использовали их в шаблоне замены. Единственный плейсхолдер с ограничением — это
А вот паттерн, который реализует подсветку и QuickFix «Replace 'if' with '?:'»:
Если у вас есть идеи полезных паттернов, то расскажите про них в комментариях. Это будет полезно для сообщества, а возможно самые интересные паттерны будут включены в следующую поставку ReSharper.
Но это еще не все. На самом деле механизм, который выполняет сопоставление с образцом, намного мощнее, чем это видно конечному пользователю. Текущие ограничения связаны с тем, что команде ReSharper пока не понятно, как правильно выразить в UI те или иные аспекты. Например, в текущей реализации нельзя найти конструкцию, в которой что-то отсутствует (например, вызов метода без какой-либо проверки, или метод определенного вида, но без атрибута). Но это можно сделать через API.
Более того, если вы пишете подсветку или QuickFix с ипользованием этого API, то вы здорово экономите свое время, т.е. вам не приходится серьезно разбираться в модели исходного кода и прочих тонкостях. Вы описываете образец в терминах синтаксиса C#, задаете параметры и получаете результат, например для «Replace 'if' with '?:'» достаточно написать такой код:
Очень просто, а главное понятно без пояснений, и не требует знаний о внутренностях ReSharper. Если бы вы стали писать этот код без использования Search With Pattern API, то вам бы потребовалось знание о том как устроено синтаксическое дерево, об интерфейсе
Вы ищете код по образцу, делаете дополнительные проверки (например, невыразимые через Search With Pattern API) и можете развешивать подсветки!
Search With Pattern API доступен через интерфейс
s == null || s == String.Empty
". Вы можете воспользоваться регулярными выражениями и попытаться сделать Find Text, но такие регулярные выражения будут выглядеть монструозно и, наверняка, содержать много ошибок (например, не будут учитвать возможность комментариев в почти каждой точке программы). Очевидно, что для решения этой задачи нужен какой-то другой вид поиска, который бы знал о синтаксисе языка, системе типов и не заставлял бы разработчика изучать какой-то новый синтаксис языка запросов.Умный поиск
В ReSharper 5.0 появился новый тип поиска «Search With Pattern», который позволяет искать куски кода по шаблону, причем на части этого шаблона можно накладывать ограничения. Например, для выражений можно указать тип, а для аргументов их предполагаемое количество.
Давайте рассмотрим конкретный пример. Будем искать в вашем коде все выражения "
enumerable.Count() > 0
", где enumerable
— это любое выражение типа IEnumerable
.Если бы вы решали эту задачу через Find Usages, то вы бы шали вызовы методаCount()
, а соответственно вам пришлось бы глазами просматривать дестяки или сотни вызовов — это утомительно и чревато ошибками. Find Text выглядит несколько лучше, но если подумать о том, что искомое выражение может быть записано с переводами строк, комментариями, а методCount()
в вашем проекте реализуют объекты разных типов, то становится понятно, что и он не подходит.
Откройте окно «Search With Pattern» (Resharper -> Find -> Search With Pattern) и введите в текстовое поле следующий шаблон:
$enumerable$.Count() > 0
Строка
$enumerable$
— будет подсвечена красным. Дело в том, что в знаки "$" заключаются имена плейсхолдеров, во время поиска на месте такого плейсхолдера будет ожидаться любой текст, соответствующий заданным ограничениям: типу плейсхолдера и его параметрам. В нашем случае на месте $enumerable$
может быть любое выражение типа IEnumerable
. Но для начала нам нужно определить этот плейсхолдер. Для этого нажмите «Add Placeholder», выберите «Expression», в поле «Name» введите "enumerable
" (имя плейсхолдера без знаков доллара). В «Expression Type» введите "IEnumerable
" (начните вводить имя типа, и решарпер сам подскажет вам варианты). Не забудьте поставить галочку «Or derived type».Буквально за несколько секунд, без знаний о регулярных выражениях мы создали шаблон для поиска. Но есть еще одна приятная и очень мощная вещь: обратите внимание, что под полем редактирования шаблона есть галочка «Match similar constructs». Если эта галочка установлена, то происходит поиск не только точных совпадений с образцом, но и сематически идентичных конструкций. Например, конструкции "
a > 0
" и "0 < a
" семантически идентичны. В нашем случае эту галочку разумно оставить установленной, ведь вам все равно как результат метода Count()
сравнивается с нулем.Все готово! Теперь можете нажать кнопку «Find» и посмотреть на результаты.
Умная Замена
Такой мощный поиск без функции замены был бы не полным, ведь интересно не просто найти все нехорошие места в программе, но и заменить их правильным кодом. Для этого в окне «Search With Pattern» нажмите кнопку «Replace». Появится поле для ввода паттерна замены. В этом поле можно написать любой корректный с точки зрения языка текст, также можно использовать плейсхолдеры. Введите в это поле:
$enumerable$.Any()
Теперь нажимайте кнопку Replace!
Делаем из паттерна поиска подсветку и QuickFix
Теперь у вас есть шаблон для поиска и шаблон для замены. Логично сделать из этого подсветку и QuickFix. Для этого в окне редактирования паттерна просто нажмите кнопу «Save». Ваш паттерн сохранится в «Patterns Catalogue». Этот каталог можно просто использовать для хранения часто используемых шаблонов, а можно сделать из него мощное средство для создания собственных анализов.
Если вы откроете каталог (ReSharper -> Tools -> Patterns Catalogue), то сможете для своего паттерна настроить настроить текст подсказки, текст, который будет показываться в QuickFix и тип подсветки. Установите для своего паттерна все эти параметры.
Все! Подсветка работает! Теперь весь код, соответствующий вашему шаблону, будет подсвечиваться налету! А на подсветке будет появляться соответствующий QuickFix!
Примеры паттернов поиска
Паттерн поиска, который упрощает выражения:
В этом примере мы использовали плейсхолдеры для типа, выражения и идентификатора. При этом не задали никаких ограничений на них, но зато использовали их в шаблоне замены. Единственный плейсхолдер с ограничением — это
$seq$
, он ограничен типом IEnumrable
.А вот паттерн, который реализует подсветку и QuickFix «Replace 'if' with '?:'»:
Если у вас есть идеи полезных паттернов, то расскажите про них в комментариях. Это будет полезно для сообщества, а возможно самые интересные паттерны будут включены в следующую поставку ReSharper.
Пишем расширения к ReSharper легко и быстро
Но это еще не все. На самом деле механизм, который выполняет сопоставление с образцом, намного мощнее, чем это видно конечному пользователю. Текущие ограничения связаны с тем, что команде ReSharper пока не понятно, как правильно выразить в UI те или иные аспекты. Например, в текущей реализации нельзя найти конструкцию, в которой что-то отсутствует (например, вызов метода без какой-либо проверки, или метод определенного вида, но без атрибута). Но это можно сделать через API.
Более того, если вы пишете подсветку или QuickFix с ипользованием этого API, то вы здорово экономите свое время, т.е. вам не приходится серьезно разбираться в модели исходного кода и прочих тонкостях. Вы описываете образец в терминах синтаксиса C#, задаете параметры и получаете результат, например для «Replace 'if' with '?:'» достаточно написать такой код:
var myMatcher = searcherFactory
.CreatePattern("if ($condition$) { $x$ = $expr1$; } else { $x$ = $expr2$; }")
.AddExpressionPlaceholder("condition")
.AddIdentifierPlaceholder("x")
.AddExpressionPlaceholder("expr1")
.AddExpressionPlaceholder("expr2")
.CreateStatementMatcher();
* This source code was highlighted with Source Code Highlighter.
Очень просто, а главное понятно без пояснений, и не требует знаний о внутренностях ReSharper. Если бы вы стали писать этот код без использования Search With Pattern API, то вам бы потребовалось знание о том как устроено синтаксическое дерево, об интерфейсе
IIfStatement
, о том, чем IExpression
отличается от IReferenceExpression
, о том как сравнивать выражения на эквивалентность (вам надо сравнить два вхождения выражения $x$
), и много других сложных вещей. Вы ищете код по образцу, делаете дополнительные проверки (например, невыразимые через Search With Pattern API) и можете развешивать подсветки!
Search With Pattern API доступен через интерфейс
StructuralSearchEngine
. Если будет достаточное количество заинтересованных людей, то я могу в следующей статье привести небольшой пример того, как можно с его помощью легко создавать собственные подсветки и QuickFix.