Question

Consider the following analyzer:

public void AnalyzeNode(SyntaxNode node, SemanticModel semanticModel, Action<Diagnostic> addDiagnostic, CancellationToken cancellationToken)
{
    var throwStatement = node as ThrowStatementSyntax;

    var isObjectCreationExpression = throwStatement.Expression is ObjectCreationExpressionSyntax;
    var obj = throwStatement.Expression as ObjectCreationExpressionSyntax;

    var isCorrectTypeOfExpression = (obj.Type as IdentifierNameSyntax).Identifier.Text == typeof(ArgumentException).Name;
}

With SyntaxKind.ThrowStatement as the Kind of Interest.

obj should be null if the thrown exception has not been declared right there in the form new Exception() but is rather presented as throw e where e is a previously declared exception.

This in turn will throw a NullReferenceException when obj.Type is called right after.

Example in question:

static void Method1()
{
    throw new ArgumentException();
}

static void Method2(ArgumentException e)
{
    throw e;
}

The first throw will pass the analyzer just fine, but the second one will cause obj to be null since it is not of type ObjectCreationExpressionSyntax.

In the sandbox Visual Studio environment this will show up as an information message:

The User Diagnostic Analyzer 'FormattingFixes.EmptyArgumentException.ArgumentExceptionAnalyzer' threw an exception with message 'Object reference not set to an instance of an object.'.

In this short sample it's easy to tell where the problem is, but in a less contrived example it will be harder to spot. The line and column are both 1, not helpful.

In "traditional" programming, your environment automatically shows you where the runtime exception was thrown and what the values are at that point in time. I can put a random breakpoint somewhere in my code, look at all values every time it's hit and try to deduce it from there, but this doesn't scale well once the amount of nodes goes much higher than these 2.

How can we easily find what line in the code causes a runtime exception?

Was it helpful?

Solution

So you should have still gotten a break in, but if you didn't a few things to check:

Go under the Debug menu, and choose Exceptions. You'll see a column for "Thrown" or "User-unhandled". Either find NullReferenceException with Find, and check a checkbox for "thrown". That'll cause VS to break as soon as a NullReferenceException is thrown. If you want to be really aggressive, you can tell it to break on all exceptions.

If that's still not working, go under Tools > Options, Debugging, General and clear "just my code". The caveat here is this will break on all exceptions, including ones in parts of VS that aren't even your fault. (Sadly, we throw lots of exceptions in lots of various places.)

If you want, feel free to file a bug so we can make our message include the stack trace and line/column so it's easier to debug.

And since I'm here: your code did

var isCorrectTypeOfExpression = (obj.Type as IdentifierNameSyntax).Identifier.Text == typeof(ArgumentException).Name;

Be careful with the syntax checks -- what happens if I write throw new System.ArgumentException()? The proper approach is to get the semantic model and bind the ObjectCreationExpression to figure out what the real type is. (It'll also mean you work in the case of aliases, if you care.)

OTHER TIPS

Use following steps to get the line number which throws an exception.

  1. Get the StackTrace for the exception.
  2. Get the top frame for the stack.
  3. Get the line number from the stack frame.

Following is the code snippet.

try
{

    //TODO
    throw new Exception();
}
catch (Exception ex)
{
    var stacktrace = new StackTrace(ex, true);
    var frame = st.GetFrame(0);
    var filelinenumber = frame.GetFileLineNumber();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top