Skip to content

Instantly share code, notes, and snippets.

@nzgeek
Created September 29, 2015 08:53
Show Gist options
  • Select an option

  • Save nzgeek/9c24abfe6623626aeff1 to your computer and use it in GitHub Desktop.

Select an option

Save nzgeek/9c24abfe6623626aeff1 to your computer and use it in GitHub Desktop.
Debug helper extensions for Roslyn code analyzers
using System.Diagnostics;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
namespace MyCodeAnalysis
{
/// <summary>
/// Extension methods that help with debugging.
/// </summary>
static class DebugExtensions
{
/// <summary>
/// Writes a debug trace entry with information about the syntax node and its location.
/// </summary>
/// <param name="node">The syntax node to log information about.</param>
/// <param name="context">An optional string giving context about the node.</param>
/// <remarks>A debug trace entry is only written if the code is compiled in the Debug configuration.</remarks>
public static void DebugLog(this SyntaxNode node, string context = null)
{
#if DEBUG
var location = node?.GetLocation();
var syntaxKind = node?.Kind().ToString();
DebugLog(context, node, syntaxKind, location);
#endif
}
/// <summary>
/// Writes a debug trace entry with information about the syntax node or token and its location.
/// </summary>
/// <param name="nodeOrToken">The syntax node or token to log information about.</param>
/// <param name="context">An optional string giving context about the node or token.</param>
/// <remarks>A debug trace entry is only written if the code is compiled in the Debug configuration.</remarks>
public static void DebugLog(this SyntaxNodeOrToken nodeOrToken, string context = null)
{
#if DEBUG
var location = nodeOrToken.HasValue() ? nodeOrToken.GetLocation() : null;
var syntaxKind = nodeOrToken.HasValue() ? nodeOrToken.Kind().ToString() : null;
DebugLog(context, nodeOrToken, syntaxKind, location);
#endif
}
/// <summary>
/// Writes a debug trace entry with information about the syntax token and its location.
/// </summary>
/// <param name="token">The syntax token to log information about.</param>
/// <param name="context">An optional string giving context about the token.</param>
/// <remarks>A debug trace entry is only written if the code is compiled in the Debug configuration.</remarks>
public static void DebugLog(this SyntaxToken token, string context = null)
{
#if DEBUG
var syntaxItem = token.HasValue() ? (object)token : null;
var syntaxKind = token.HasValue() ? token.Kind().ToString() : null;
var location = token.HasValue() ? token.GetLocation() : null;
DebugLog(context, syntaxItem, syntaxKind, location);
#endif
}
/// <summary>
/// Writes a debug trace entry with information about the syntax trivia and its location.
/// </summary>
/// <param name="trivia">The syntax trivia to log information about.</param>
/// <param name="context">An optional string giving context about the trivia.</param>
/// <remarks>A debug trace entry is only written if the code is compiled in the Debug configuration.</remarks>
public static void DebugLog(this SyntaxTrivia trivia, string context = null)
{
#if DEBUG
var syntaxItem = trivia.HasValue() ? (object)trivia : null;
var syntaxKind = trivia.HasValue() ? trivia.Kind().ToString() : null;
var location = trivia.HasValue() ? trivia.GetLocation() : null;
DebugLog(context, syntaxItem, syntaxKind, location);
#endif
}
/// <summary>
/// Writes a debug trace entry with information about a syntax item and its location.
/// </summary>
/// <param name="context">An optional string giving context about the syntax item.</param>
/// <param name="syntaxItem">The syntax item that information is being logged about.</param>
/// <param name="syntaxKind">A string indicating the type of syntax item.</param>
/// <param name="location">The location that the syntax item appears in the file.</param>
private static void DebugLog(string context, object syntaxItem, string syntaxKind, Location location)
{
if (string.IsNullOrEmpty(context) && syntaxItem == null)
return;
var logMessage = new StringBuilder();
// Add the context to the log entry, if one was provided.
if (!string.IsNullOrEmpty(context))
{
logMessage.Append(context);
logMessage.Append(' ');
}
// If no syntax item was provided, we can't say much about it.
if (syntaxItem == null)
{
logMessage.Append("<nothing>");
}
else
{
// Start the position information with the kind of syntax item.
logMessage.Append('[');
logMessage.Append(syntaxKind ?? syntaxItem.GetType().Name);
logMessage.Append('@');
// The location could be unknown, or it could be a line/column position.
if (location == null)
{
logMessage.Append("???");
}
else
{
// Line/column are 0-based. Make them 1-based so they match the position in the Visual Studio
// status bar.
var startPosition = location.GetLineSpan().StartLinePosition;
logMessage.Append(startPosition.Line + 1);
logMessage.Append(',');
logMessage.Append(startPosition.Character + 1);
}
logMessage.Append("] ");
// Add the node text (first line only).
var itemParts = syntaxItem.ToString().Split('\r', '\n');
logMessage.Append(itemParts[0]);
// If it spans over multiple lines, only add the first line followed by an ellipsis.
if (itemParts.Length > 1)
logMessage.Append(" ...");
}
Debug.WriteLine(logMessage.ToString());
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment