Tuesday, July 13, 2004

This is a preview of a new Reflector addin to well let you search for Program Patterns in your assemblies. The addin is mainly an adaptation to .Net of the article from Santany Paul and Atul Prakash, "A Framework for Source Code Search using Program Patterns".

What are Program Patterns ?

In their article, the authors use a pattern language to specify high-level patterns for making queries on the source code. It smells like regular expression but it operates on statements and expression instead of strings. The basic pieces of the pattern languages are:

  • # describes any expression,
  • @ describes any statement,
  • more to come here...

More specific patterns, like if, while, throw,  are also defined. In fact, for each interface of the Reflector.CodeModel namespace, a corresponding pattern class is needed. Let's illustrate this with a simple example of query: Find all occurence of a if followed by a throw statement.
In the original paper notation, the pattern is defined as follows:

if (#) throw #;

Of course this will have to change a bit for C#.

C# implementation

In my implementaiton, the IPattern interface defines a Program Pattern:

public interface IPattern
{
    bool Match(Object target);
}

The interface is intentionaly simple to enable great extensibility. This interface is then specialized for IStatement, IExpression, IBlockStatement, etc.. For example, the pattern to match a throw statement will be implemented as follows:

public class ThrowExceptionStatementPattern : StatementPattern
{
    // pattern for the expression that is throwed. Pats is a helper class
    private ExpressionPattern expression = Pats.AnyExpression;
    ...

    public override bool Match(IStatement statement)
    {
        // trying to cast statement to IThrowExceptionStatement
        IThrowExceptionStatement th = statement as IThrowExceptionStatement;
        // did not cast, no match
        if (th==null)
            return false;
        // expression did not match, no match
        if (!this.Expression.Match(th.Expression))
            return false;
        // we have a match!
        return true;
    }
}

To ease up things, a helper class containing static methods (Pats) takes care of creating those objects.

Implementing the example

Implementing the example is now just a matter of putting the pieces together. We need a pattern for the if, one for the throw and a pattern that will recurse in all the statements:

// provided by Reflector
IMethodDeclaration visitedMethod = ...
// if pattern
ConditionStatementPattern ifthen = Pats.If();
// setting the Then pattern
// StatementInBlock says the pattern should be in the IBlockStatement
// Pats.Throw() returns a ThrowExceptionStatementPattern 
ifthen.Then = Pats.StatementInBlock(Pats.Throw());
// a pattern that will recurse all the statements
RecursiveStatementPattern rec = Pats.Recursive(ifthen);

// launching the seach
rec.Match(visitedMethod.Body);

Testing the example

The above pattern has been applied to the following class where 2 methods match the pattern, and 2 do not match it:

public class CodeMatchingTest
{
    public void If(bool arg)
    {
        Console.WriteLine("This method has a if");
        if (arg)
            Console.WriteLine("arg is true");
        else
            Console.WriteLine("arg is false");
    }
    public void Throw()
    {
        throw new Exception();
    }
    public void IfThrow(bool arg)
    {
        if (arg)
            throw new Exception();
    }
    public void IfThrowHiddenInsideWhileLoop(bool arg)
    {
        int i = 0;
        while(i<10)
        {
            if (i>5)
                throw new Exception();
            Console.WriteLine(i.ToString());
        }
    }
}

And the result in Reflector is displayed below. As expected, IfThrow and IfThrowHiddenInsideWhileLoop have matched the pattern.

Monday, June 06, 2005 5:49:54 PM UTC
Blogs/ Personal
Monday, June 06, 2005 5:49:54 PM UTC
Wow, superb!
<br>Thanks.
Diana
Friday, August 19, 2005 11:17:15 AM UTC
Hi Jonathan
Is it possible to download this add-in some where?

Thanks
Hung Pham
Comments are closed.