Thursday, June 25, 2009

The ElementEnumerable Class

In our previous tutorial we showed how to use Methods like AllVariables and AllExpressions to extract information from some code in order to furnish the Code Metric subsystem of Coderush with additional Metric possibilities.

But what happens if you want to gather something that is not catered to explicitly? Perhaps you’d like to write an ExtremeMetric which counts Try..Catch information?

Let me introduce you to my good friend ‘ElementEnumerable’

ElementEnumerable

ElementEnumerable is exactly what it sounds like. It a class  which is used for Enumerating Elements. It’s constructor takes a scope element, a Type filter and an option to recurs or not.

It implements IEnumerable and when used as an Enumerator, it will enumerate across the scope you handed it, stopping to pass out anything which matches what you asked it to filter.

We can create a MethodEnumerable for the current class thus…
-------------------------------------------------------------
e.Value = New ElementEnumerable(SomeClass, GetType(Method)).Cast(Of Method).Count 
-------------------------------------------------------------
Our Variable Enumerator will be only slightly more complicated..
-------------------------------------------------------------
e.Value = New ElementEnumerable(SomeMethod, GetType(Variable), True).Cast(Of Variable).Count
-------------------------------------------------------------
The reason for the True param at the end is to allow The ElementEnumerable to recurse inside things like if statements in order to find variables declared deeper that the top level of the method in question.

In our previous example of a MethodEnumerable, we can safely assume that the methods we would like to find are all immediate children of the start point. If we had not made this specification, we could well have returned methods belonging to a nested class.

So if we wanted to count Try Statements, we could use….
-------------------------------------------------------------
e.Value = New ElementEnumerable(Method, GetType([Try]), True).Cast(Of [Try]).Count
-------------------------------------------------------------

…and of course you can do all kinds of calculations before you actually set this value.

So why don’t you go nuts and invent your own metric. Any questions? Just let me know :)


How To: Build your own CodeRush Metric

Well it’s been a long time, but I think I’ve finally found something I can turn into simple plugin.
-------------------------------------------------------------Note: This tutorial assumes that you are familiar with LINQ, are coding your plugin in VS2008 and targeting a system with .Net 3.5 installed.
-------------------------------------------------------------

We’re going to provide a count of the number of variables declared in a given method.

This is an entirely contrived example. In the real world it might be used as an indicator of how complex a method is. However, you could also use the “Maintenance complexity” or “Cyclomatic Complexity” that comes with CodeRush :)

This theory this metric should involve:

  • Iterating through every node within the AST (Abstract syntax tree) looking for items representing variables.
  • Count these items and pass this count back to the DXCore for rendering by CodeRush

In practice this is a lot simpler than it sounds.

First you’ll need to create a new plugin. Once this is done, you’ll want to add a CodeMetricProvider to the design surface of the plugin. It can be found on the “DXCore: Extensions & Providers” tab of your toolbox and looks like this.CodeMetricProviderOnce dropped on the design surface, we should set a few properties.

ProviderName: ‘VariableCountMetric’
DisplayName: ‘Variable Count’
Description: Counts the variables declared within the member.
MetricGoal: Members
Warning: 10

Then handle the single event ‘GetMetricValue’.

The Theory

Your goal within the GetMetricValue, is to set e.Value based on some measureable quality of e.LanguageElement.

You could do anything here.. random numbers, length of member name, characters in method, characters in method if it were rendered in a different language :P All sorts.

In this case we will examine e.LanguageElement (the method) and calculate the number of variable declarations within it.

The “Warning” property is to give Coderush a value which is considered excessive for this metric.

Simples! :D

The Practice
Ok so how to count variables in a method?
Well the simplest way is…
-------------------------------------------------------------SomeMethod.AllVariables.Cast(Of Variable).Count
-------------------------------------------------------------

So add this code to you handler and you’re done…
-------------------------------------------------------------Dim Method As Method = TryCast(e.LanguageElement, Method)
If Method IsNot Nothing Then
      e.Value = Method.AllVariables.Cast(Of Variable).Count
End If
-------------------------------------------------------------

Ta Da…. Seriously go try it out…

If you get this to run successfully, then go have a look at some of the other “All” methods that hang off the method class..

Like AllExpressions, AllFlowBreaks, AllParameters or AllStatements. Similar methods exist on the ‘Type’ class.

Note: Remember to load your plugin via the “plugin manager” if you set it to “Load manually” when you created it (as you should have)


Friday, June 19, 2009

Coderush 9.2.0 Speed and Memory Improvements FTW!!

Recently Mr Mark miller posted on his blog about how much more efficient the next version of CodeRush was going to be.

In summary -> ZOMG This will be so cool".

So at the earliest opportunity, I requested access to the latest daily build of said product and was granted access

A few notes up front:

  • If you’re going to try this out, you need to uninstall 9.1
  • This version of 9.2 is a TRIAL version. It will expire eventually. Not sure when. I didn’t ask.
    • *YOU CANNOT* install this as a registered user… Nobody (Including me) has been given this level of access.
    • *Install as Evaluation* It works just as well :D
  • This is not the release version. It is a daily build. It did not go through the usual levels of testing.
  • There is a bug in this version which prevents some things from working unless you have installed everything (including the free bits)
  • The timings below were not done using a stopwatch but by me counting (1..1000..2..1000)

I have a solution I use every day at work so I thought I’d use that as the basis for my testing.

Some facts about this solution

  • It’s written in VB.net
  • It contains 13 projects (6 Class libraries, 7 Webapps/Webservices)
  • There are no project references in this solution
    • This is strange I know.
    • Instead we reference dlls built using nant as a part of our external build process.
  • According to this LOC program my solution has…
    • Number of lines = 61,358
    • Number of code files = 503
    • Number of code-generated lines = 6,563
    • Number of user-entered blank lines = 4,355
  • The .vb code files total some 3.5 MB(ish)

Some facts about the machine I use at work

WorkMachine
(click Image for large version)

WorkMachineDetail 
(click Image for large version)

So first I needed a baseline. I disabled all addins and re-loaded studio.

Studio at rest with nothing loaded, occupied [34,020 - 50,684]

(Note: Figures represent the values shown in Process Explorer for Private Bytes and Working set respectively)

I loaded my solution and timed how long it took to reach zero CPU usage within process manager.
It took approx 15 seconds to load my solution and afterward memory usage had risen to [150,740 - 193,556]
I built the solution and memory raised a little further to [170,640 - 209,184]

So this was the baseline.

What followed was several repetitions of this procedure inserting the loading of CodeRush 9.1 and 9.2 into the sequence.

In each case I restarted studio and reloaded CR where appropriate.

I will not detail everything here, but will present the summary figures.

CoderushFigures 
(click Image for large version)

So how does this break down?

Well basically it’s all in the bottom right hand corner.

So for my modest project… (after having built an on-disk cache during the first load of any given solution)

  • CodeRush has practically eliminated any previous overhead it added to the solution‘s load time. So it’s now as quick to use CodeRush as to not use it. :)
  • CodeRush saves between 45.2% and 58.5% memory depending on how you choose to judge it.

It is worth noting that these memory savings are likely to skyrocket as the complexity of your software increases.

Indeed, I have already seen a post on twitter from a user who has something more like 80% savings on memory.

I know I’m happy with my results … How about you ? … What results do you get ? :)


Wednesday, June 10, 2009

CR_ClearAllMarkers

I am something of an anomaly….

I’ve been using Coderush now for about 3 years and I *still* don't get ‘markers’. I'm an Idiot.. I have some kind of mental block. I just can't think that way for some reason.

I expect to remain ignorant/oblivious of their use in my day to day life, until I eventually meet up with Mark Miller some day and he has the opportunity to beat me until I come to my senses :D.

In the mean time however, I suffer from a particularly mild OCDesque affliction which cannot deal with their presence on my screen.

Because I don’t use them, they are noise. Small noise, but noise none the less. The fact that they are small and noisy is part of why I don’t like them… the other part is that they are everywhere.

I was explaining my psychosis to @Fredrikeriksson on twitter. I mentioned that whenever I see these little blue and red triangles in my code I have a compulsion to repeatedly hit Esc in order to clear my system of them.

Unfortunately for me, this has a side effect of causing my caret to lurch about inside my code like a demented puppy that just found a fresh roll of toilet paper. It was whilst explaining this little disadvantage, that I realized that I could probably knock up a plugin to deal with this problem in less than 2 minutes.

As it turns out, I was wrong.

It took a full 2 minutes and 15 seconds to develop and test. However the result of this short period of development is now available for all who feel the need to partake.

I give you CR_ClearAllMarkers.

In all honesty, it’s a sham of a plugin really. All I did was create a new action which called a pre-existing method within the DXCore. as usual all the hard work had already been done for me by the Coderush/DXCore team themselves.

In any case, I would like to take this opportunity to apologize to the Coderush Team. Sorry guys it's nothing personal :)


Monday, April 27, 2009

CR_HelloWorld – Your first DXCore plugin

So for your first DXCore Plugin, we’ll show you the traditional “Hello World” program…plugin style.

We’ll show you how you can execute any managed code from a plugin – Fun stuff

First up you’ll need to Create a Vanilla plugin. From here you’ll be able to add all the relevant pieces to create CR_HelloWorld.

 

Ok first Step… ensure you’re looking at the designer view of your plugin. If you’ve not renamed it this will be the “Plugin1” (cs or vb) file.

DXCoreDesignSurfaceSmall

Next locate the ‘Action’ component in your toolbox and place one on the designer surface.

DXCoreControls

The set an appropriate name and a few properties:

actSayHelloWorld

Finally handle the “Execute” Action and do something within it.

This seems appropriate:

-------------------------------------------------------------
Private Sub actSayHelloWorld_Execute(ByVal ea As ExecuteEventArgs) Handles actSayHelloWorld.Execute
    MessageBox.Show("Hello World")
End Sub
-------------------------------------------------------------

Ok well that’s the majority of the work done.

However you’re going to need some way to activate this action…

So hit F5 to run up a new instance of studio to debug your new plugin.

Once this new copy of studio is running, be sure to ensure your plugin is actually running in memory.

Next we will attach your new action to a shortcut….

Open up the DXCore options screen (DevExpress\Options) Note – You may need to use the previously mentioned 'registry hack' to get the DevExpress menu to show up, if you’re running one of the Free DXCore based products.

Next select the IDE\Shortcuts page from the left hand side and you should see something like the following.

DXCoreOptionsShortcuts

In the shot you can see (Click to view full image) I have created a new ‘keyboard shortcut’ ( which I did via a context menu within the shortcut tree) and then I have filled out the Key1 and command options.

Now you can have your copy of Studio say “Hello World” whenever you choose :)

Obviously this is a something of a contrived example but, as you can see, it would be easy to have studio execute any managed code you care to dream up in a similar way.


How do I test my DXCore Plugin?

A simple enough question but it deserves a bit of thought.

You’ll recall from my previous post on creating a plugin, I suggested indicating that your plugin was a “Community plugin”

The reason for this was to prevent multiple copies of studio from loading and thus locking the plugin dll that you were working on.

So this leads you to a small problem… How to get the DXCore to load your plugin if you have explicitly asked it not to?

Well here’s how…

Simply open up the plugin manager from the DevExpress\Tool Windows\Plug-in Manager.

 

Side note: If you are using one of the free DXCore products, then you may not have such a menu. In order to acquire access to this most useful of facilities you’ll need to do a bit of registry hackery.
The following solution was provided in the AlexS (Another very helpful DevExpress employee)  in the DevExpress IDE Tools Forums
-------------------------------------------------------------
Please invoke the Registry editor, add the "HideMenu" DWORD value to the following Registry key, and set its Value to 0:

HKEY_LOCAL_MACHINE\SOFTWARE\Developer Express\CodeRush for VS\9.1
This should make the "DevExpress" menu visible.
-------------------------------------------------------------

DevExpressPluginManagerMenuOption

…to reveal this…

PluginManagerHelloWorld

Simply double click the entry you would like to load and, after confirmation your action, the DXCore will load your plugin.

All should now be good and you can commence testing your plugin..


What is a DXCore Action?

An action is one of the components you can drop on your plug-in design surface.

When you do so it looks like this ....

DXCoreAction

It can be triggered via either a mouse or keyboard shortcut (found in the IDE shortcuts page of the options screen) or placed on a menu (for example the context menu of the Code Editor)

It is a derivative of ‘system.component’ adding a few properties…

 DXCoreActionProperties

…and events…

DXCoreActionEvents

Some of these are worth drawing special attention to.

Properties
ActionName: The name of the action as displayed to UI like the commands dropdown in the IDE\Shortcuts options page.
ButtonText: What text would you like to represent this action when it is placed on a menu?
CommonMenu: A list of some of the more common menus found around VS.
ParentMenu: An alternative to CommonMenu. Use the name of any menu you know of, to place the action on that rather than one of the ‘common’ ones.

Note: The placing of Actions on menus is entirely optional and CommonMenu and ParentMenu are mutually exclusive options.

Events
Execute: The main event (so to speak :)). Fired whenever the assigned shortcut is triggered or the representative menu item is chosen. This is how the Action does it’s stuff.

In my next post I will walk you through your first actual plugin … Yes we will be starting slow, but we’ll ramp up fairly quickly as the posts flow… so you’ll be knocking out your own custom refactorings and the like pretty soon.


Wednesday, April 15, 2009

CodeRush 9.1.3 Community plugin support.

In the latest drop of the IDE Tools, the community folder experience has been enhanced.

Previous versions of the installer placed the community folder within the DevExpress folder structure (beneath Program Files).

This new location has several benefits:

1.> Creating a new plugin should (untested) no longer require you to launch VS with Admin rights. since your plugin ins not being rebuilt under program files :)

2.> Uninstall will not remove community plugins. (Shouldn’t have anyway but this really seals it.)

3.> Community folder will be immune to path changes as the version numbers of the IDE Tools increase.

As of 9.1.3, the Default folder for community plugins is now “{My Docs}\DevExpress\IDE Tools\Community\Plugins”


Monday, April 13, 2009

Creating a new DXCore Plugin

[Updated: This post has been updated to account for some small changes in the 9.1.3 release]

There are certain steps you must follow in order to create a DXCore plugin of any kind. This blog post will outline and explain those steps.

So the first step is to create the right sort of project.

If all is installed correctly you should be able to find the 2 available projects (‘Standard Plug-in’ and ‘Tool Window Plug-in’) in the DXCore section under either the Visual Basic or Visual C# sections in the New Project dialog.

Initially I’ll suggest that you pick ’Standard Plug-in’ as you can always add the Tool window later if you need to.

FileNewDXCorePlugin

Once you’ve given your plugin a Name, and hit Ok, you’ll be presented with the Plug-in Project settings dialog.

 InitialPluginSettings913_thumb5

Plug-in Type: System Plug-in: will cause your plugin to be deemed a ‘System plugin’ Duh! But what does this mean? Simply put, system plugins are loaded ahead of non system plugins. 90% of all plugins have no need to do this… I have yet to use this facility in any plugin I have written.

Plug-in Type: Plugin: Will cause your plugin to be built to “IDETools\System\DXCore\Bin\PlugIns\”. I’m guessing that this is something that DevExpress do themselves. Although I see no reason not to use the Community option.

Plug-in Type: Community Plug-in: is a new option with version 9.1.3. This is due, from what I can see, to the new Community Plugin Path option. This option sets the compile path of your new plugin, to your current community folder (Setup when you first loaded CodeRush or RefactorPro or DXCore after installing 9.1.3.) This means that, if you accepted the default, your plugin will exist under your ‘My Docs’ folder and as such will not require you to Launch Visual Studio with Admin rights in order to compile your plugin. – You should pretty much always pick this option.

Checking ‘Load manually’ will cause an entry to be added to the ‘plugin manager’ (another plugin), which in turn will prevent the DXCore from automatically loading your plugin.

Why would you do this?

Well, suppose that whilst developing your plugin, you are suddenly required to do something else. (Heaven forbid that anything should come ahead of this most important work). What you do is you go and immediately fire up another copy of VS and you load what ever you need into that session and off you go.

The trouble is that (assuming that you’ve compiled your plugin at least once) DXCore has now loaded a copy of your unfinished/unpolished plugin into memory. This might not be a problem but there are 2 ways I can think of that might mean it is…

1.> You’re writing the most killer refactoring known to man, and you’ve just completed the ‘DeleteAllThisUselessCrap’ routine but haven’t quite gotten around to writing the ‘InsertGloriouslyShineyCode’ and if activated, without taking suitable precautions then you could be up the swanny.

2.> You might want to tab back to to some more development on your plugin whilst you’re waiting for the results of your latest check-in on your ‘Important project’, but unfortunately the copy of VS hosting your ‘Important Project’ is maintaining a lock on your plugin’s dll and as such you’ll be unable to compile it, much less test it.

So in order to avoid these scenarios, I always tick the ‘Load Manually’ tick box which then ensures that the DXCore never *automatically* loads my plugin. Then when I launch a copy of VS for testing it, I locate it in the plugin manager and double click it in there. At this point DXCore wakes up, notices the plugin and loads it. In doing this you have only loaded your plugin into the address space of a single instance of VS, which exists entirely for the purpose of testing your plugin. This also means that when you shut down this single copy of VS, you’ll be able once again to resume development of your plugin. Great huh?

Note: This setting is local to your development installation only and will not affect any users of your plugin.

Default Load Type

I asked AlexZ (one of the great brains behind the DevExpress IDE Tools) about the ‘Default load type’ setting (and most everything else as well :) – Alex is a great source of info) and he had this to say:

On Demand - plugin is loaded when some event happens for which plugin should work. e.g. if you plugin contains some action - then it will be loaded only when action is being executed. Or it may define context or string provider or any other provider - and plugin will be loaded when provider is really accessed.
On Idle - Plugin will be loaded on editor idle, IOW when VS editor is being idle.
At start-up - Plugin will be loaded on start-up - however it will add time to overall loading time.

So which one should you select.. well the answer is it depends.. Personally I typically leave the default of ‘On demand’ in place as this means your plugin should not affect the start-up time of VS. This might mean that you have a minor slow down as you activate your plugin for the first time, but it will not contribute to slowing down the start up time of VS.

So to summarize… I recommend that you tick the ‘Load manually’ option and leave everything else (except perhaps the name) exactly as default … then hit Ok

At this point VS churns away and provides you with a nice clean plugin project ready for you to create the greatest plugin known to man… after all .. that’s what you were going to do right :)

I am now contractually obligated to make you wait until the next instalment before I reveal anything else :)


DXCore Plugin Types

A single DXCore plugin dll can perform a single simple task or many different functions. These functions are added to a plugin by adding various components to it’s design surface. These components will need various properties set and events handled, but the process is typically quite simple.

These components include:

  • Action – A simple object which represents any arbitrary piece of Code you like. Placable on many of the VS menus and assignable to a keyboard or mouse shortcut (optionally in combination with a context) using the DXCore IDE\Shortcuts option page.
  • RefactoringProvider – Used to add items to the ‘Refactor’ Menu in RefactorPro
  • CodeProvider – Used to add items to the ‘Code’ menu in CodeRush. It differs from the RefactoringProvider in that by convention items placed on this menu are allowed to alter the functionality of the code they affect
  • IssueProvider – Used to add ‘Code smells’, ‘Warnings’ and the like to the CodeRush ‘Code Issues’ feature.
  • CodeMetricProvider – Used to provide additional metrics for both inline metrics and the Metrics tool window.
  • ContextProvider – Used to add items to the Context Tree. This in turn is used to indicate suitability of Templates, Shortcuts and other Coderush facilities.
  • NavigationProvider – Used to add extra Items to the Navigate SmartMenu
  • SmartTagProvider – Used to add a new section to the DXCore SmartTag menu. Items like the existing ‘Refactor’ and ‘Code’ menu sections
    StringProvider and TextCommand – used to enhance existing features like templates, selection embeddings, Selection Inversions and others. Both perform some function, but the StringProvider returns a value to it’s calling mechanism where the TextCommand does not.

Depending on the type of functionality you are after, you may not need to place any additional component on your plugin. The plugin object itself has several properties and events that, when properly used, can provide some very useful effects.

Over the course of the next few blog posts I am hoping to provide some insight into the general process of creating a plugin, as well as the facilities provided by each of these components.


Thursday, April 02, 2009

Community Plugins for CodeRush 9.1

DXCore 9.1 introduces a different directory structure for the IDE Tools (CodeRush, RefactorPro) based on it.

Similarly you will need to move any 3rd party plugin assemblies you rely on to “C:\Program Files (x86)\DevExpress 2009.1\IDETools\Community\PlugIns”

Please adjust this path according to the setup of your own machine (System/install drive, x86 Vs x64)

All community plugins I have tried so far appear to work fine. If you know better please feel free to contact me via the comments.