I am trying to make a code analyzer which checks for fully qualified using statements. This link has been incredibly helpful, and the basis for my solution (How can I get the fully qualified namespace from a using directive in Roslyn?) but I am running into a problem when I try to access the location of the symbol for the using directive. My code looks like this:
private static void AnalyzeModel(SemanticModelAnalysisContext semanticModelAnalysisContext)
{
var semanticModel = semanticModelAnalysisContext.SemanticModel;
var root = semanticModel.SyntaxTree.GetRoot();
// compare each using statement's name with its fully qualified name
foreach (var usingDirective in root.DescendantNodes().OfType<UsingDirectiveSyntax>())
{
var symbol = semanticModel.GetSymbolInfo(usingDirective.Name).Symbol;
var fullyQualifiedName = symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
if (fullyQualifiedName.Contains(GlobalTag))
{
fullyQualifiedName = fullyQualifiedName.Substring(GlobalTag.Length);
}
if (usingDirective.Name.ToString() != fullyQualifiedName)
{
// for each name that is not fully qualified, produce a diagnostic.
var diagnostic = Diagnostic.Create(Rule, symbol.Locations[0], symbol.Name);
semanticModelAnalysisContext.ReportDiagnostic(diagnostic);
}
}
}
The problem is the symbol.Locations[0]
only contains items in metadata, not items in source. This leads to the following error:
Assert.IsTrue failed. Test base does not currently handle diagnostics in metadata locations.
My source in my unit tests looks like this:
private const string incorrectSourceCode = @"
namespace System
{
using IO;
using Threading;
}";
Why are there no items in symbol.Locations
that are in source? Is there another place I can get this location? I've tried using symbol.ContainingSymbol.Locations[0]
or symbol.ContainingNamespace.Locations[0]
, but those are not referring to the using specific using that I am interested in. I've been pulling out my hair over this for hours, and some clarity would be very greatly appreciated.
Thanks in advance!
Symbol
contains MetadateLocation
, so if you want to see SourceLocation
just retrieve it from the appropriate SyntaxNode
:
var diagnostic = Diagnostic.Create(Rule, usingDirective.Name.GetLocation(), symbol.Name)
instead of
var diagnostic = Diagnostic.Create(Rule, symbol.Locations[0], symbol.Name)