Highlighting Custom Patterns with ReSharper

A new feature that has shipped with ReSharper 5 is the Structural Search and Replace. It is a way for us to locate certain patterns in our code, and optionally replace them. However, it is more than just a Find and Replace. It allows us to somehow extend ReSharper’s inspection settings by offering us means to identify patterns and highlight them.

As many of you know, ReSharper offers a series of Suggestions, Hints, Warnings and Errors when it detects certain code patterns. For instance, when explicitly declaring a variable, ReSharper suggests you use var (and with good reason)

image

These are configurable, in that you can tell ReSharper whether you want them to be displayed as hints, suggestions, warnings or errors, which is done via ReSharper | Options | Inspection Severity

image

Setting it to Show as error for instance will display a red (or whatever color you have configured) underlining and the right-hand side border will display the a Red box indicating an error in the file.

SNAGHTML12140a89

If we now combine this with Solution Wide-Analysis, ReSharper will also indicate an error in the solution.

image

 

Extending Inspections

Have you ever encountered the following?

image

This is a perfect candidate for using String.Format. How about this?

image

Did you know StringBuilder has an AppendFormat? You might know that, I might, but maybe other developers don’t. It would be good to provide developers with a hint or suggestion that they could use AppendFormat. Up to version 5 of ReSharper, the inspections were limited to what ReSharper provided out of the box and the only thing we could do to extend this functionality was create/use a plug-in We can now use Structural Search and Replace to accomplish this. Let’s see how it works.

1. Open up a Solution (I’m using BlogEngine.NET but feel free to create your own with some sb.Append calls).

2. Select ReSharper | Tools | Pattern Catalog.

SNAGHTML1228e7ce

By default, the Pattern Catalog is empty.

3. Click on the Add Pattern

SNAGHTML122b7d0a

4. In this first sample, all we want to do is highlight code, so click on the Find button at the top to switch the dialog to Find mode only.

SNAGHTML122d5169

The Search Pattern is what we’ll use to define what we are looking for. The Description is a text which helps us identify the pattern easily in the Catalog. The box on the right is for place holders which we’ll see in a moment.

5. Enter the following pattern in the Search Pattern editor

image

What this does is indicate the pattern we are looking for. The values surrounded with $’s (same notation as that used in Live Templates) represent placeholders. A placeholder can be an expression, statement, type, etc. If it is red, it means it has not yet been defined (next step).

6. Click on the Add Placeholder button on the right box and select Expression, and enter the following values:

SNAGHTML12c3cb9a

We are indicating that the placeholder sb (first one used) is an expression of type System.Text.StringBuilder

7. Click on the Add Placeholder button to define the second placeholder, args. Select Argument and enter the following values:

SNAGHTML12c63dfb

We can optionally indicate whether we want to limit the number of minimum or maximum arguments.

If both placeholders have been defined correctly, the Search pattern box should now look like this:

SNAGHTML12c9a0e2

(we’ve entered a description at the bottom)

8. We need to define the type of severity we want. In this case we want it to be marked as a Suggestion. We do that using the Pattern severity dropdown and then click Save

Our Pattern Catalog should now be updated to reflect this new pattern

SNAGHTML12caa7e4

9. At this stage we can either close the Patterns dialog or Search for a pattern. Let’s see what happens if we click Search now button.

SNAGHTML1376eb2e

A Find Results window is displayed highlighting everywhere where ReSharper can find a pattern match. But what about the Pattern severity? Where does that come into play? Let’s double-click on one of the entries:

image

See the highlighting of the sb.Append call? Set the Pattern Severity to Error and that will display in Red.

image

Turn on Solution-Wide Analysis and that will list as an error!

So as we can see, the Structural Search (we haven’t replaced yet), allows us to monitor for certain code patterns in our projects. Potentially we could use it to detect certain code smells.

Fixing things up

Now that we have certain patterns located, and even highlighted, how do we go about fixing things? As we saw in the previous screenshots, we have a little icon pop up when placing the cursor on the line:

image

This context action however doesn’t offer us anything in order to fix the situation, i.e. there is no QuickFix. The reason is obvious: ReSharper doesn’t know what a fix is. Let’s show it!

1. Open up the Patterns Catalog and Edit the previously created Pattern

2. Click on the Replace button to open up the Replace editor at the bottom

SNAGHTML1384f656

3. Enter the following text in the Replace pattern section

image

4. Provide a description (this is what the hint of the QuickFix will dispaly)

image

5. Click on the Save button

Locate the previous sb.Append call and place the cursor on top of the line. We can now see a QuickFix icon appear (A red bulb in this case since it’s an Error)

image

Alt+Enter and we’re done!

image

 

Global Fix

What we’ve just done is a manual local fix, that is, locate the offending entry and hit Alt+Enter to apply a QuickFix. We can do this at a global scope by using the Pattern Catalog tool window.

1. Undo the prefix fix (so as to have several instances)

2. Open up the Patterns Catalog

3. Select the recently created Pattern and click on Search now. This time, instead of the Find Results dialog, we get a Replace dialog which displays all matching patterns and a Replace button

SNAGHTML138b5c29 

4. We can select the entries we want replacing (by default all checked). Click Replace

We’re done! ReSharper will now replace all occurrences. So we’ve applied a QuickFix globally.

 

There’s more

What we’ve seen here is just a simple example of how to improve on a call to a class. We can of course do more complex searches, allowing us to identify code smells, etc. The pattern we created in this tutorial is actually included in a Patterns catalog you can download from the documentation section of our web site (or click here for direct link). All you need to do is unzip it and import the XML from the Patterns Catalog window (Import button). Currently, Pattern Catalogs are PER solution.

There’s much more planned for Structural Search and Replace in vNext and we are always happy to receive feedback, so please try it out, and let us know what you think.

This entry was posted in How-To's, ReSharper Tips&Tricks and tagged , , . Bookmark the permalink.

20 Responses to Highlighting Custom Patterns with ReSharper

  1. Bryan says:

    Does this work in VB? In VB the syntax for sb.AppendFormat is the same as for c# so it should work. However, when I click search now I get a message that it Cannot parse pattern.

  2. Roni says:

    Great feature.
    Can you use macros though, in the replace pattern? For my usage I need to apply a transformation to one of the method’s arguments. Is that possible?

  3. Hadi Hariri says:

    @Bryan

    Currently it only supports C#, but it will have support for VB in vNext.

  4. Hadi Hariri says:

    @Roni,

    Not yet. The editor is quite limited currently but we’re planning a lot enhancements. Could you also please make sure any requests you have are logged? http://youtrack.jetbrains.net

  5. Ryan Rodemoyer says:

    It looks like this is on a per solution basis? I have to import the pattern settings for each solution I want to use them in?

  6. Hadi Hariri says:

    @Ryan,

    Yes. Currently it’s per solution

  7. Phil Motuzko says:

    string.Format vs String.Format

    In my code I have both cases. How do I make the pattern work in both cases?

  8. Hadi Hariri says:

    @Phil,

    It should work with either.

  9. Phil Motuzko says:

    Well…

    with $sb$.Append(String.Format($args$)) it only works on tmpBuilder.Append(String.Format(“aaa{0}”, 7));

    with $sb$.Append(string.Format($args$)) it only works on both string.Format and String.Format

    kind of weird

    What about int vs Int32?

  10. Joe White says:

    @Phil, do you have “Match similar constructs” checked?

  11. Unfortunately pattern search/replace has never worked for me. I always get a message saying “Can not parse pattern”.

  12. Victor Kropp says:

    @Phil, I can explain this weirdness: string is a keyword, that can not mean anything other than System.String, while String in your pattern my refer to some custom class String in your own namespace. Assumption that String is always System.String will give false-positive matches.

  13. Trupik says:

    I want to match something like
    public $TYPE$ $PROPERTY_NAME$
    but I want the suggetion to appear while standing on PROPERTY_NAME isntead while standing on the word public. Can this be achieved?

  14. Hadi Hariri says:

    @Rory

    Your issue was solved with latest build right?

  15. Hadi Hariri says:

    @Trupik

    It underlines entire line.

  16. GreenMoose says:

    Re: “ReSharper suggests you use var (and with good reason)”

    Consider this code
    IService { IFoo GetIt(); }
    //…
    var foo = service.GetIt();
    if (foo != null )
    service.StoreIt();

    //Now we should refactor IFoo to be an int instead (for some weird reason), so we start with finding all references for IFoo. The above is not found since var is used. So we continue refactor GetIt() to return int instead of IFoo and return 0 where it previously returned null. Compile – no errors, but hopefully our unit tests aren’t 100% coverage any longer and/or failing, so we can discover that something now is wrong.

    //If we instead use:
    IFoo foo = service.GetIt();
    if (foo != null )
    service.StoreIt();

    //We a) find the reference for IFoo before we continue refactoring b) We get compile error for refactoring since IFoo cannot be implicitly converted to an int.
    //In both a and b we are helped to spot the foo != null and can change it to foo != 0.

    Thus, usage of var keywoard IMHO should not be encouraged if it can be avoided :-).

  17. Eddie says:

    Hi

    Well I am at my wit’s end trying to get the ‘search’ feature to work on the Pattern Catalog window. I have added patterns that I know 100% work because they work on the Structural Search / Replace dialog – but once I save it to the pattern catalog and try to search off there I keep getting the infamous “Cannot parse pattern” error message. This has happened on more one computer – it’s not just my environment. The funny thing is, you can tell the patterns do work because ReSharper highlights code issues matched by the patterns! Clearly this is a bug that needs fixing guys. It’s been occurring since the feature was introduced as far as I recall.

    This is most frustrating! I have a large solution with 57 projects and this feature would be an incredible asset but the problem I am experiencing renders it useless. I even tried removing all projects except for the core library, unloaded ReSharper (you know ReSharper_ToggleSuspended), reloaded, and still it does not work.

    JetBrains ReSharper 5.1 Full Edition
    Build 5.1.1753.4 on 2010-10-15T15:51:30

    PS: Don’t get me wrong; I love the structural search and replace. One suggestion though: when a pattern is indeed wrong and cannot be parsed, it would be awesome if the UI informed the user as to *why* it cannot be parsed.

  18. Hadi Hariri says:

    @Eddie,

    I fully agree. We need to get this bug fixed and drastically improve error reporting on the pattern, which is already being done.

    Could I please ask you to send us the patterns you are using and a small project to reproduce? If you could log it in http://youtrack.jetbrains.net and send me the ID, I’ll make sure it will be looked at. My email is hadi at jetbrains.

    Thanks.

  19. Eddie says:

    @Hadi Hariri

    Thanks. I have a repro and I will submit it via the link you provided above. I’ll email you once I have done that!

    Regards,

    Eddie

  20. Eddie says:

    @Hadi Hariri,

    I submitted the repro. I have raised issue RSRP-199662 and have emailed you.

    Regards,
    Eddie

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>