DCSIMG
CodeRush Plugin – Navigate to Implementation Part 3 - .NET Geek

.NET Geek

"It is upon the Trunk that a gentleman works" - Confucius

CodeRush Plugin – Navigate to Implementation Part 3

In this part we’ll look at the Implementors class. As we described in part 1, a the Navigation Provider will call into our plugin twice. Once to give us the chance to make our plugin available to the user and a second time if the user selected one of our menu items. When the Navigation provider raises the event CheckAvailability we need to do two things.

  1. Check if this plugin is available in the current context.
  2. Alter the menu displayed so our options are available to the user.

In step one we will first check if we are positioned on a method call who’s declaring type is an interface. If we are we need to find all classes that implement that interface and add them to the menu. Here’s the code:

internal class Implementors : IEnumerable<Class>, IEnumerable

{

    private List<Class> _implementors;

    public Implementors()

    {

        _implementors = new List<Class>();

    }

    public void Load(LanguageElement element)

    {

        Reset();

        if (!OnCall(element))

            return;

        IElement declaringType = element.GetDeclaration().Parent;

        Interface abstraction = declaringType as Interface;

        if (abstraction == null)

            return;

        LoadImplementors(abstraction);

    }

    public int Count

    {

        get { return _implementors.Count; }

    }

    private void Reset()

    {

        _implementors.Clear();

    }

    private static bool OnCall(LanguageElement element)

    {

        return (element is MethodReferenceExpression);

    }

    private void LoadImplementors(Interface abstraction)

    {

        ITypeElement[] decendants = abstraction.GetDescendants();

        foreach (ITypeElement implementor in decendants)

        {

            Class implementingClass = implementor.GetDeclaration() as Class;

            if (implementingClass != null)

            {

                _implementors.Add(implementingClass);

            }

        }

    }

    public IEnumerator<Class> GetEnumerator()

    {

        foreach (var item in _implementors)

        {

            yield return item;

        }

    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()

    {

        return GetEnumerator();

    }

}

Let’s have a look at the Load method. We first need to clear any classes that were found from previous invocations of the plugin. Since this code in our plugin is always run as the result of a user request, we don’t have to be to hung up on optimizations. It would be much different if we needed to paint on the screen or do some other performance critical operations
Next we check if the caret is currently located on a method call.

private static bool OnCall(LanguageElement element)

{

    return (element is MethodReferenceExpression);

}

Ok, so how did I know what to check for? CodeRush ships with a niftly tool that will display the parsed source tree as it looks to CodeRush.

image

The Source Tree viewer is extremely useful!

Checking the context

Next we check if the method is invoked on an Interface declaration.

IElement declaringType = element.GetDeclaration().Parent;

Interface abstraction = declaringType as Interface;

if (abstraction == null)

    return;

So if we are located on a method that is called on an interface, we can look for descendants of this Interface. (I actually think of them as implementors. Maybe I should stick with the CodeRush terminology as that is the ubiquitous language of CodeRush plugins.

Loading the implementors

private void LoadImplementors(Interface abstraction)

{

    ITypeElement[] decendants = abstraction.GetDescendants();

    foreach (ITypeElement implementor in decendants)

    {

        Class implementingClass = implementor.GetDeclaration() as Class;

        if (implementingClass != null)

        {

            _implementors.Add(implementingClass);

        }

    }

}

One issue I had is that much of the data is exposed as methods and not as properties. The implication of that is that you can’t expand them in the visualizers in Visual Studio. Am I missing something?

So how do you find your way through the CodeRush object model?

NDepend DependencyGraph Snapshot

(DevExpress.CodeRush.StructuralParser)

First of all, CodeRush ships with a decent number of plugin source code. That is usually the first place I look. The Source Tree explorer is indispensable. The documentation is not extensive enough to be of much help, but hopefully that will change. As I mentioned in an earlier post, Mark Miller is doing online tutorials which are very good and there’s also a session on DnrTV which is good. DevExpress is hosting an online discussion forum for asking questions related to their products. Note that this is a peer2peer (customers helping customers) forum. Despite that, DevExpress developers are monitoring the forums and they jump in with assistance.

An online community forming?
A few developers that are developing plugins for CodeRush have started an open source project DxCoreCommunityPlugins that aggregates plugins. Looks promising. The project has some good initiatives despite the fact that some of the plugins seem to have matching functionality in CodeRush. (Probably developed after the plugin was released)

That concludes this part. In the next and last part I’ll walk through some of the code in the Navigator class.

 

 

 

 

 

Share this post : del.icio.us it! digg it! dotnetkicks it!

Comments

.NET Geek said:

This is the last post in series on developing the navigate to an implementing method plugin. Here are

# December 4, 2008 2:48 AM
Leave a Comment

(required) 

(required) 

(optional)

(required) 


Enter the numbers above: