Skip to content

DebuggerDisplayAttribute analyzer

Sergey Teplyakov edited this page May 16, 2016 · 1 revision

DebuggerDisplayAttribute is one of the most underutilized attributes ever. This attribute is incredibly useful for debugging purposed because it can show not just default ToString representation of the object but something more meaningful for person during debugging session.

But because DebuggerDisplayAttribute takes just a string, it is very easy to mess up with it's content. And as always ErrorProne.NET could be in handy in this case.

ErrorProne.NET now understands this attribute and will warn (maybe it should be an error?) in following cases:

Provided string has invalid format

DebuggerDisplayAttribute takes a format string that should have following structure: Text: {expression}, i.e. user may specify any text she wants follows by expression in curly braces. So if the string is invalid, ErrorProne.NET will warn you about it:

[DebuggerDisplay("X: {ToString(), nq")]
//               ~~~~~~~~~~~~~~~~~~~~
// Can't find corresponding close brace '}' in the input string
public class CustomType
{}

Unknown format specifier

User may provide additional format specifier to DebuggerDisplayAttribute inside {}. The only one that I'm aware of is nq which stands for 'no quotes': DebuggerDisplay("{ToString(), nq}". And of course, if you'll mess with it you'll get a warning:

[DebuggerDisplay("X: {ToString(), dq}")]
//               ~~~~~~~~~~~~~~~~~~~~
// Expression 'ToString(), dq' is invalid:
//   Unknown expression specifier 'dq'. Known specifier is 'nq'.
public class CustomType
{ }

Expression is invalid

Ok, those two cases were pretty simple, now let's consider more advanced stuff.

DebuggerDisplayAttribute can reference almost everything. It can any expression that references any static/instance members including fields, methods and properties. More over, you may call any methods and even provide any arguments there! The only rule for methods is that it should be non-void (yep, method can return anything and the result would be translated to string).

But because this attribute just takes a string it is relatively easy to mess with it without noticing.

ErrorProne.NET will show warning if the expression provided to the attribute is invalid:

[DebuggerDisplay("X: {ToDisplayString(42)d}")]
//               ~~~~~~~~~~~~~~~~~~~~
// Expression 'ToStrinString(42)d' is invalid: 'Unexpected token 'd''
public class CustomType
{ }

NOTE Please keep in mind that expressions provided to DebuggerDisplayAttribute are language specific. So you should avoid them and just provide a function invocation that will do all the required computations.

Expression is valid but member is unknown

String-based expressions are very error-prone (pun intended) and refactoring unfriendly. It means that someone can change the name of the field/property/method or just change method signature and compiler will not notice. Compiler can't help in this case, but ErrorProne.NET can:

[DebuggerDisplay("X: {ToDisplayString(string.Empty)}")]
//               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Expression 'ToStrinString(string.Emmpty)' is invalid: 
//    Argument 1: cannot convert from 'string' to 'int'
public class CustomType
{
    private string _internalStringRepresentation = "foo";

    private int ToDisplayString(int someArguments)
    {
        return someArguments;
    }
}

Or member is invalid:

[DebuggerDisplay("X: {_internalStringRepr}")]
//               ~~~~~~~~~~~~~~~~~~~~~~~~~~
// Expression 'ToStrinString(string.Emmpty)' is invalid: 
//    'The name '_internalStringRepr' does not exists in current context'
public class CustomType
{
    private string _internalStringRepresentation = "foo";
}

Even when method returns void:

[DebuggerDisplay("X: {ToDisplayString()}")]
//               ~~~~~~~~~~~~~~~~~~~~~~~~
// Expression 'ToStrinString(string.Emmpty)' is invalid: 
//    'Cannot implicitely convert type 'void' to 'object''
public class CustomType
{
    private void ToDisplayString()
    {}
}