I started learning about Roslyn Code Analysis recently. I went through provided sample codes. My question is following:
Is there a way how to get XML documentation comment of a symbol loaded from a referenced library?
Sample code I worked with is FAQ(7)
. The goal is to get documentation comment of, let us say, a Console.Write
function.
public void GetWriteXmlComment()
{
var project1Id = ProjectId.CreateNewId();
var document1Id = DocumentId.CreateNewId(project1Id);
var mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
var solution = new AdhocWorkspace().CurrentSolution
.AddProject(project1Id, "Project1", "Project1", LanguageNames.CSharp)
.AddMetadataReference(project1Id, mscorlib);
var declarations = SymbolFinder.FindDeclarationsAsync(solution.Projects.First(), "Write", true).Result;
var decFirst = declarations.First();
var commentXml = decFirst.GetDocumentationCommentXml();
}
The sample code works well for some methods - it gets the documentation text. But for methods, such as Console.Write
, it uses NullDocumentationProvider
and therefore returns empty string.
I have found I can load the MetadataReference
with TestDocumentationProvider
instance as following:
var mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location,
default(MetadataReferenceProperties), new TestDocumentationProvider());
where TestDocumentationProvider
implements Microsoft.CodeAnalysis DocumentationProvider
abstract class.
private class TestDocumentationProvider : DocumentationProvider
{
protected override string GetDocumentationForSymbol(string documentationMemberID, CultureInfo preferredCulture, CancellationToken cancellationToken = default(CancellationToken))
{
// To-Be-Done
}
}
Now the question narrows to how to read documentation using documentationMemberID
?
Update: In Roslyn 2.0 you can use XmlDocumentationProvider.CreateFromFile
.
The only way I can think of is using Reflection to create a FileBasedXmlDocumentationProvider
(or otherwise copying its implementation from GitHub). You'll also need to search for the reference assemblies, since the load location of the framework assemblies does not contain documentation.
private static MetadataReference FromType(Type type)
{
var path = type.Assembly.Location;
return MetadataReference.CreateFromFile(path, documentation: GetDocumentationProvider(path));
}
private static string GetReferenceAssembliesPath()
{
var programFiles =
Environment.GetFolderPath(Environment.Is64BitOperatingSystem
? Environment.SpecialFolder.ProgramFilesX86
: Environment.SpecialFolder.ProgramFiles);
var path = Path.Combine(programFiles, @"Reference Assemblies\Microsoft\Framework\.NETFramework");
if (Directory.Exists(path))
{
var directories = Directory.EnumerateDirectories(path).OrderByDescending(Path.GetFileName);
return directories.FirstOrDefault();
}
return null;
}
private static DocumentationProvider GetDocumentationProvider(string location)
{
var referenceLocation = Path.ChangeExtension(location, "xml");
if (File.Exists(referenceLocation))
{
return GetXmlDocumentationProvider(referenceLocation);
}
var referenceAssembliesPath = GetReferenceAssembliesPath();
if (referenceAssembliesPath != null)
{
var fileName = Path.GetFileName(location);
referenceLocation = Path.ChangeExtension(Path.Combine(referenceAssembliesPath, fileName), "xml");
if (File.Exists(referenceLocation))
{
return GetXmlDocumentationProvider(referenceLocation);
}
}
return null;
}
private static DocumentationProvider GetXmlDocumentationProvider(string location)
{
return (DocumentationProvider)Activator.CreateInstance(Type.GetType(
"Microsoft.CodeAnalysis.FileBasedXmlDocumentationProvider, Microsoft.CodeAnalysis.Workspaces.Desktop"),
location);
}
I've used something similar in RoslynPad.