Working with Namespace Names in a Code Analyzer

Sep 19, 2015

Let's imagine we wanted to create an analyzer that compared the name of the namespace to the path of the folder in which the file it resides. If the namespace doesn't match the folder structure, then we should raise a diagnostic. As we have seen in a previous post, you can get at the file name for the code you are analyzing from a SyntaxTreeAction. To start, we'll register a new SyntaxTreeAction and get the file path. We can also take that path and turn it into something that resembles a namespace declaration:

Now that we have the path to use for comparison, we can get the namespaces in the file and then perform the comparison. We can get all of the namespaces in a SyntaxTree by using the OfType extension method and find all NamespaceDeclarationSyntax node types. Note: Make sure you use DescendantNodes and not ChildNodes to ensure you get all nested namespace declarations.

You might be tempted to just use the ns.ToFullString() method to get the name of the namespace, however, this does not work for nested namespaces. For example, if we have the code:

#!cs
namespace Foo
{
namespace Bar
{
}
}

The full namespace for Bar is Foo.Bar, but the ns.ToFullString() method will only return Bar. To properly get the full name, we need to ask our friend the SemanticModel for the Symbol for this SyntaxNode and then we can get the DisplayString from there. Getting the semantic model requires a little massaging of our registration code.

The SemanticModel is available off of the Compilation object. As we discussed in the "Working with Types in Your Analyzer" post, you can access the Compilation object by registering for a CompilationStartAction and then registering your other actions from that context.

And that is everything. I think this post really shows some of the power of using the SyntaxTree and the SemanticModel together to put together an analyzer that can process real world code. This post was inspired by a question I answered on StackOverflow and took a few iterations to get right. I thought I would share the process of how I got there so others can learn from it. If you have done something written a similar analyzer or have great examples of using the SemanticModel and SyntaxTree together, let's talk about it in the comments below.