Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can an analyzer validate that namespaces properly match the file location

Tags:

c#

roslyn

It is conventional to name namespaces in a C# solution such that they match the default namespace for the project plus the name of any sub-directories for the containing file.

For example, a file called Haddock.cs is in a directory called Fish and the default namespace (in the first tab of the project's properties in VS) is Lakes then the file should contain something like

namespace Lakes.Fish
{
    public class Haddock
    {
    }
}

The StyleCop analyzers project contains a nice rule that validates that the class name matches the file name.

Is there any way I can write a rule that verifies that the namespace name is correct?

like image 472
Olly Avatar asked Sep 15 '15 18:09

Olly


Video Answer


1 Answers

You can access the file path from a SyntaxTreeAction using the Tree.FilePath off of the SyntaxTreeContext.

Once you have the path, you can then parse that and compare it with the name of all of the Names of the NamesSpaceDeclarationSyntax nodes in the tree.

Unfortunately, I do not think there is a way to get at the default namespace for a project at this time.

Here is a quick sample I threw together that does what it can so far. The processing/comparing of the path to the namespace is rudimentary and there is probably a better way to do it, but this should get you started.

public override void Initialize(AnalysisContext context)
{
    context.RegisterCompilationStartAction((compilationSyntax) =>
    {
        compilationSyntax.RegisterSyntaxTreeAction((syntaxTreeContext) =>
        {
            var semModel = compilationSyntax.Compilation.GetSemanticModel(syntaxTreeContext.Tree);
            var filePath = syntaxTreeContext.Tree.FilePath;

            if (filePath == null)
                return;

            var namespaceNodes = syntaxTreeContext.Tree.GetRoot().DescendantNodes().OfType<NamespaceDeclarationSyntax>();
            var parentDirectory = System.IO.Path.GetDirectoryName(filePath);

            // This will only work on windows and is not very robust.
            var parentDirectoryWithDots = parentDirectory.Replace("\\", ".").ToLower();

            foreach (var ns in namespaceNodes)
            {
                var symbolInfo = semModel.GetDeclaredSymbol(ns) as INamespaceSymbol;
                var name = symbolInfo.ToDisplayString();

                if (!parentDirectoryWithDots.EndsWith(name.ToLower().Trim()))
                {
                    syntaxTreeContext.ReportDiagnostic(Diagnostic.Create(
                       Rule, ns.Name.GetLocation(), parentDirectoryWithDots));
                }
            }
        });
    });
}
like image 146
John Koerner Avatar answered Oct 21 '22 04:10

John Koerner