Welcome to MSDN Blogs Sign in | Join | Help

jaredpar's WebLog

Code, rants and ramblings of a programmer.

Syndication

News

Now Reading

Expert F#

What's a better book to read when learning F#?

Essential WPF

Thus far the best book I've read on WPF. Gets right down to working with WPF and the goals/history.

Purely Functional Data Structures

Reading this book makes me feel like I'm back in college. It will really get your mind going and is best read with a whiteboard handy.


Saved by PowerShell

Recently I made a very large update to our code base.  Our code base lacked a standard way of guarding entry and exit points into the various components.  Having said guards is useful for error handling, tracing, reducing redundancy, etc ...  The edit standardized our entry points by adding start/end macros to our entry point functions.  In addition to other house keeping, the macros also created an HRESULT variable named "hr".  Example below.

#define MY_ENTRY_GUARD() HRESULT hr
#define MY_ENTRY_EXIT() return hr

Ran suites, everything passed, checked in.  Then I got an email from another dev who spent some time tracking down a bug related to this check-in (sorry Calvin).  He discovered one scenario my fix did not take into account.

SomeMethod
{
  MY_ENTRY_GUARD();
  if ( somecondition ) {
    HRESULT hr = E_FAIL; // shadows the first hr
  }
  MY_ENTRY_EXIT(); // returns unmodified hr
}

The double declaration of the variable "hr" is not an error or even a warning in C++.  Instead the inner "hr" shadows the outer and hence the rest of the method doesn't update the "hr" which is actually returned.  So now I had to find every place in this change where a nested hr was declared.  Did I mention this edit was huge?  Going through by hand would not only be time consuming, it would also be very error prone. 

At first I considered parsing out the C++ and doing basic brace matching to look for shadowing "hr" variables.  I ruled that out due to the amount of time I would need to invest in the script to take into account comments, string literals, etc ...  Really I didn't need brace matching, I really just needed to know when I entered and left a method.  Almost all C++ methods have their opening and closing braces on the first column.  Writing a script to detect this is trivial. 

Script took about 5 minutes to write and 10 to run in the code base.  Saved me countless hours of error prone reviews.  Thank you PowerShell.

Find-DoubleHr.ps1:

param ( $argFileName = $(throw "Need a file name") )

function Do-Work() {
    $i = 0
    foreach ( $line in (gc $argFileName) )  {
        new-tuple "Text",$line,"LineNumber",$i
        $i++
    }
}

function Do-Parse() {
    begin {
        $inMethod = $false
        $seenHresult = 0
        $seenMacro = 0
    }
    process {
        $tuple = $_
        if ( $inMethod ) {
            switch -regex ($tuple.Text) {
                "^}" {
                    $inMethod = $false
                    if ( ($seenHresult -ne 0 )-and ($seenMacro -ne 0) ) {
                        "Found a double {0},{1}" -f $seenHResult,$seenMacro
                    }
                    $seenHresult = 0
                    $seenMacro = 0
                    break
                }
                ".*MY_ENTRY_GUARD.*" {
                    write-debug ("Macro: {0} " -f $tuple.Text)
                    $seenMacro = $tuple.LineNumber
                    break
                }
                "HRESULT.*\Whr\W" {
                    write-debug ("HResult: {0}" -f $tuple.Text)
                    $seenHresult = $tuple.LineNumber
                    break
                }
            }
        }
        elseif ( $tuple.Text -match "^{" ) {
            $inMethod = $true
        }
    }
}

"Processing $argFileName"
Do-Work | Do-Parse

Published Wednesday, May 07, 2008 8:00 AM by Jared Parsons

Filed under: ,

Comments

No Comments

New Comments to this post are disabled
Page view tracker