Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the ReSharper Find Usages command search resx files?

Tags:

resharper

When I right-click a symbol and run the Find Usages ReSharper command, ReSharper will often seem to spend most of its time searching resx files. The majority of the time during which the progress dialog is visible, the file names shown in that dialog are various .resx files in the solution.

screenshot

Is ReSharper actually searching .resx files? Why would it do this, and why would it take so long? Can I alter this behavior?


Setup: ReSharper 8.2.0.2160 C# Edition. Visual Studio 2013 Premium.

What I've tried:

  • Adding resx as a mask to the Code Inspection Items To Skip R# preference, but that doesn't make a difference
  • Find Usages Advanced, uncheck the Textual Occurrences option. Doesn't make a difference
like image 334
Mike Mertsock Avatar asked Mar 12 '15 14:03

Mike Mertsock


1 Answers

The answer to this is all due to ReSharper's underlying architecture. When processing files, ReSharper will build an abstract syntax tree, and each node in the tree can have one or more references to an element in the semantic model. In other words, the Foo in the expression new Foo(42) will have a reference to the semantic element describing the class called Foo. Each file will have lots of references, as any usage of an element (variable, parameter, method, property, CSS class, HTML colour, file system path, and more) has one or more references to the declaration of that element.

These references are very powerful. They enable Ctrl+Click navigation, by simply navigating to the target(s) of the reference. They can provide code completion by displaying the candidate targets that would satisfy a reference at the current location in code.

And of course, they also power Find Usages, by finding all references that target a particular element. But this requires working backwards, from the target to the reference. The brute force approach would require checking the target of every reference in every file, trying to find the target. This clearly wouldn't scale, and the data set is too big to cache.

To make Find Usages run in a sane timescale, ReSharper also maintains a word index, of all words used in all files (this also helps with normal Go To navigation). When you invoke Find Usages on a symbol (such as EnterDate in the screenshot in the question), ReSharper uses the word index to narrow down the files it needs to search - it would look up EnterDate, and only use those files that include the word. Once it has a reduced subset of files to search, it needs to find any references that target the original element. To do this, it walks the syntax tree of each file in the subset. Each node is checked for references that match the name of the symbol we're looking for, e.g. EnterDate. If it matches, the reference is resolved, and the target is checked to see if it matches the same element - the EnterDate class, or property or whatever it actually was. If it does point to the expected target, it is added to the collection of usages, and gets displayed to the user.

(Things are slightly more complex than this, in that a reference might have multiple names, e.g. if you try and find usages on [Pure], ReSharper needs to find any usages of both Pure or PureAttribute. Fortunately, these alternative names are also stored in the word index, and used to help reduce the files to be searched. When checking the references, all of the alternative names are checked)

So, if you have a .resx file that contains the text EnterDate, it will be searched for a reference to the EnterDate element you're looking for - ReSharper will walk the syntax tree of the .resx file, and check each reference to see if it matches EnterDate.

We check all files, even if it seems obvious to the user that the target element can't possibly be used in that file, because we allow references to be cross language. That is, a VB file can reference a C# element, or a HTML file can reference a CSS element, or an XAML file reference a C# method element, and so on. So there is no filtering on "sensible" usage. For example, if EnterDate is a class, you as a user can tell that it's not likely to be in a .resx file, but ReSharper has no way of knowing that. After all, it's perfectly fine to use a class name in the type attribute of a web.config file, or as a parameter to typeof in a VB file. Or a plugin could add a reference provider that allows for usages of typenames in .resx files. So, we keep things simple and search all candidate references, even though it might look odd in the progress dialog.

like image 57
citizenmatt Avatar answered Jan 01 '23 18:01

citizenmatt