How is TestCaseSource attribute validation implemented?

When using TestCaseSource attribute in Resharper 7 it recognizes that method name specified as the parameter of the attribute doesn't exist - I guess it is Resharper's 7 feature because I haven't seen that before. How is it implemented? I would like to make same check for my own attributes as extension if possible.

1 comment
Comment actions Permalink

Hi. Yes, this is a new analysis added in ReSharper 7. It's actually implemented in two parts, one which creates a reference between the text in the attribute and the method, and another which provides auto-completion of method names when typing in the attribute argument. You can implement both yourself in a custom plugin.

To create the reference, you need to implement IReferenceFactory and IReferenceProviderFactory. The factory is the easiest, and is just a class that both implements IReferenceProviderFactory and is decorated with the ReferenceProviderFactoryAttribute. This class creates and returns a new instance of IReferenceFactory. Now you need to implement HasReference and GetReferences, by looking at the passed in element of the abstract syntax tree of the file, and creating and returning any references. The nunit implementation (which you can look at in dotPeek - look for TestCaseSourceReferenceFactory) checks to see if the current element is a literal expression that belongs to the argument of an attribute that is a TestCaseSourceAttribute. If so, it creates an instance of TestCaseSourceReference, which implements (amongst other things) IReference. This is a reasonably complex class, and your best bet here is to just read through it in dotPeek. However, once resharper knows that the literal expression is a reference to a method, it now works for control-click navigation and find usages, and displays an invalid reference as an error.

Auto-completion is handled by a second component, implemented for nunit by TestCaseSourceReferenceSuggestionRule. This class implements ICodeCompletionItemsProvider and derives from ItemsProviderOfSpecificContext. It turns out to be quite straight forward to implement, by overriding IsAvailable to check that it's running the context of a TestCaseSourceReference, and also TransformItems, which takes in an existing completion list, takes a copy, clears the list, and then adds back in any methods from the original list, but changing the lookup item from a method item into a text item (but keeping the method item icon). The existing completion list is created by ReSharper by calling GetCompletionSymbolTable of the TestCasSourceReference.

This is quite a lot to explain in a post here - the best thing to do is to fire up dotPeek and take a look at TestCaseSourceReferenceProviderFactory, TestCaseSourceReferenceFactory and TestCaseSourceReference for references, and TestCaseSourceReferenceSuggestionRule for the auto completion.

If you run into problems, or don't understand anything that ReSharper's doing, please let me know, either here, or at resharper-plugins@jetbrains.com

Thanks
Matt

0

Please sign in to leave a comment.