# Thursday, December 16, 2004

MSN Desktop search (or other search engine) is definitely the new must-have tool for developers, specially if you work with a laaaaaaarge code base. The title is self-explaining:

  •  install MSN Desktop search,
  • set up the indexing to point the source code folders
  • wait a few hours for indexing depending on the size of your project
  • pick any class or method and write it in the search bar...

The results are just lovely! It is easy to browse, relevant and fast! 

posted on Thursday, December 16, 2004 1:24:00 PM (Pacific Standard Time, UTC-08:00)  #    Comments [9]
# Thursday, December 09, 2004

I have finally deciced to merge MbUnit.Core.dll into MbUnit.Framework.dll. This will be a minor breaking change in the next release because you will have to remove the reference to MbUnit.Core.dll.

All the attributes also have moved to MbUnit.Framework, so you don't need to use MbUnit.Core.Framework. I did this change mainly to simplify the morphing NUnitForms or NUnitAsp to MbUnit: a Replace All in Files will be sufficient to move them to MbUnit.

 

posted on Thursday, December 09, 2004 9:30:00 PM (Pacific Standard Time, UTC-08:00)  #    Comments [12]
# Sunday, December 05, 2004

Reflector.CodeMetrics dynamically loads code metrics tabs at runtime by using Reflection. This means that anybody can write his own metric whithout recompiling CodeMetrics.... an Addin API inside another AddIn api :)

Here's a quick review of the steps to get your new cool code metric started. In this example, we will display the number of arguments per method (simple example).

Setting up the project

Start a new assembly project, add references to Reflector.exe, Reflector.CodeMetrics.dll and Reflector.Helpers.dll

Creating a new CodeMetric

All code metrics implement the ICodeMetric interface (this what the CodeMetricManager looks for):

public interface ICodeMetric : IServiceComponent

{

string Name { get;}

string FullName { get;}

ComputationState State { get;}

DataTable Result { get;}

Object FindItem(DataRow row);

bool Enabled { get;set;}

CodeMetricLevel Level { get;}

event ComputationProgressEventHandler Progress;

void Compute();

void Abort();

}

Of course, you don't have to implement it from scratch. You can use the abstract base class CodeMetricBase to get started:

public class ArgumentCountCodeMetric : CodeMetricBase
{
    // setting up name, full name and level of metric
    public ArgumentCountCodeMetric()
    :base("AC","Argument Count",CodeMetricLevel.Method)
    {}

    // adding columns
    protected void AddColumns()
    {
       this.AddColumn("Argument Count");
    }

    ...
}

It is important to note that we specify that the metrics target Method (can also target Type, Module). The AddColumns method is used to all the columns you want to show in the grid.

Add the metric computation

Time to get to the real fun, computing the metric... First, we provide a method GetTestCount that returns the number of steps. This number is used to scale the progress bar:

private int GetStepCount()
{
    int count = 0;
    foreach (IAssembly assembly in this.Services.AssemblyLoader.Assemblies)
    {
       if (this.Services.CodeMetricManager.IsIgnored(assembly))
           continue;
       foreach (IModule module in assembly.Modules)
            count += module.Types.Count;    
    }
    return count;
}

It is important to note that we check for each IAssembly if it has to be ignored. This is directly linked to the checkbox control on the CodeMetrics page. Note that we coun the types only, if you show progress on methods, almost all the CPU time is spent to update the controls. Next, we write the method that create a row in the grid from a IMethodDeclaration:

private void ComputeMethod(IMethodDeclaration method)
{
    IMethodBody body = method as IMethodBody;
    if (body == null)
        return;
    this.AddRow(
        method,
        body.Parameters.Count 
        );
}

The AddRow methods will add a row in the underlying DataTable, etc...

Implementing Compute

We have all the pieces, we just need to implement Compute:

public override void Compute()
{
    base.Compute();
    int stepCount = GetStepCount();
    int count = 0;
    foreach (IAssembly assembly in this.Services.AssemblyLoader.Assemblies)
    {
        if (this.Services.CodeMetricManager.IsIgnored(assembly))
            continue;
        foreach (IModule module in assembly.Modules)
        {
            foreach (ITypeDeclaration type in module.Types)
            {
                this.OnProgress(
                    new ComputationProgressEventArgs(
                        count++,
                        stepCount,
                        "Analysing {0}",
                        type
                        )
                     );
                foreach (IMethodDeclaration method in type.Methods)
                {
                    if (this.CheckForAbort())
                        return;
                    ComputeMethod(method);
                }
            }
        }
    }
    this.Finished();
}

The metric is ready, we just need to register it to the manager when the Addin is loaded.

Setting up a package and registering CodeMetrics

Reflector looks for IPackage class when loading Addins. Reflector.Helpers contains a smart implementation of that addin that will automatically load the code metrics the assembly contains, so all you have to do is to inherit from PackagePage (well almost):

namespace Reflector.CodeMetrics
{
    public sealed class CodeMetricPackage : PackageBase
    {
        [ReflectorWindow(
        Name = "Dummy control to make Reflector happy",
        Caption = "Dummy control to make Reflector happy"
        )]
       [ReflectorCommandBar(CommandBarTarget.Tools)]
       private UserControl dummy = new UserControl();
    }
}

If you do not actually load a new window, Reflector gets pissed and unload the addin. Therefore, just add a dummy window. At this point, recompile (makes sure you target the right .Net framework), load and enjoy.

Debugging

To debug, just start Reflector as external process and break point on your code.

posted on Sunday, December 05, 2004 2:48:00 PM (Pacific Standard Time, UTC-08:00)  #    Comments [11]