File paths in a Roslyn analyzer or source generator

 
 
  • Gérald Barré

In Roslyn, a SyntaxTree represents the content of a source file. If you need to know the source file that created this SyntaxTree, you can use the FilePath property. This property represents the file path on the disk. But, the file path on the disk may not be what you want.

  • On CI, you should use reproducible builds to get deterministic paths (ContinuousIntegrationBuild=true and <SourceRoot>). In this case, the file paths used for the [CallerFilePathAttribute] and PDB are deterministic paths that do not correspond to the disk path. Instead, it should be something starting with /_/.
  • You can use the #line preprocessor directive to change the file path of the next line. This directive is often used by code generators. For instance, when a XAML file generates a C# file, the C# files contain #line directives to map the original XAML node.
C#
SyntaxTree syntaxTree = ...;

// Get the actual file path on disk
syntaxTree.FilePath;

// Get the mapped file path
_ = syntaxTree.GetLocation().GetMappedLineSpan().Path;

Another useful type is SourceReferenceResolver. You can access an instance from the Compilation instance using compilation.Options.SourceReferenceResolver. Note that it may be null.

C#
static string GetDisplayPath(this SyntaxTree tree, TextSpan span, SourceReferenceResolver? resolver)
{
    var mappedSpan = tree.GetMappedLineSpan(span);
    if (resolver == null || mappedSpan.Path.Length == 0)
        return mappedSpan.Path;

    return resolver.NormalizePath(mappedSpan.Path, baseFilePath: mappedSpan.HasMappedPath ? tree.FilePath : null) ?? mappedSpan.Path;
}

If you have an IOperation, you can get the path through the Syntax property.

C#
IOperation operation = ...;
_ = operation.Syntax.SyntaxTree.FilePath;

If you have an ISymbol, you can get the paths through the Locations property.

C#
ISymbol operation = ...;
foreach (var location in symbol.Locations)
{
    _ = location.SourceTree?.FilePath;
}

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub