10
\$\begingroup\$

I'm inspecting VBA code to find obsolete code constructs - namely explicit Call statements, like this:

Call DoSomething(42)

The "correct" code construct would be to omit the Call token and drop the parentheses - my code locates the obsolete Call statements and rewrites them like this:

DoSomething 42

I have an IdentifierReference class, which I'm using to store the context of various identifier references throughout the VBA code I'm parsing. In order for my code inspection to easily locate method calls that use the obsolete Call syntax, I have added this method to the IdentifierReference class:

public bool HasExplicitCallStatement()
{
    try
    {
        var call = ((dynamic)Context.Parent).CALL();
        return call != null && call.Symbol.Text == Tokens.Call;
    }
    catch (Exception)
    {
        return false;
    }
}

But I didn't like having to handle exceptions here, so I rewrote it in a more strongly-typed way, like this:

public bool HasExplicitCallStatement()
{
    var memberProcedureCall = Context.Parent as VBAParser.ECS_MemberProcedureCallContext;
    var procedureCall = Context.Parent as VBAParser.ECS_ProcedureCallContext;

    return HasExplicitCallStatement(memberProcedureCall) 
        || HasExplicitCallStatement(procedureCall);
}

private bool HasExplicitCallStatement(VBAParser.ECS_MemberProcedureCallContext context)
{
    if (context == null)
    {
        return false;
    }
    var statement = context.CALL();
    return statement != null && statement.Symbol.Text == Tokens.Call;
}

private bool HasExplicitCallStatement(VBAParser.ECS_ProcedureCallContext context)
{
    if (context == null)
    {
        return false;
    }
    var statement = context.CALL();
    return statement != null && statement.Symbol.Text == Tokens.Call;
}

And now I wonder... is this really an improvement?

Is there any more elegant way of dealing with different types that should be sharing an interface but aren't? ECS_ProcedureCallContext and ECS_MemberProcedureCallContext are ANTLR-generated types, nested in the VBAParser class, generated from the grammar file I'm using.

\$\endgroup\$
2
\$\begingroup\$

Going back to your original code. I think a little bit of reflection will get you out of the try catch block situation.

public bool HasExplicitCallStatement()
{
    var theObject = ((dynamic) Context.Parent);
    if(theObject.GetType().GetMethod("CALL") != null)
    {
        var call = theObject.CALL();
        return call != null && call.Symbol.Text == Tokens.Call;
    }

    return false; 
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.