Search code examples
c#nrefactory

NRefactory Find XML Doc Comments in Code


I would like to get the xml documentation that is associated to a method using NRefactory. I got my feet wet by using the following code that I found in this answer

var parser = new CSharpParser();
SyntaxTree tree = parser.Parse(code, "test.cs");

CSharpUnresolvedFile file = tree.ToTypeSystem();
foreach (IUnresolvedTypeDefinition type in file.TopLevelTypeDefinitions) {
    foreach (IUnresolvedMethod method in type.Methods) {
        Console.WriteLine(method.Name);
    }
}

However, I was taking a look at the IUnresolvedTypeDefinition interface and it does not have any "Comments" property. Also, the IUnresolvedMethod interface does not have any "Comments" property. I do know that it is possible to retrieve the comments because I did so by using the WinForms application that is associated to the CodeProject article found here

The author of the demo does not use the "ToTypeSystem()" method. Instead, he traverses the tree. Below are some snippets of what he does:

SyntaxTree tree = parser.Parse(line, "demo.cs");

                    foreach (var element in tree.Children)
                    {
                        MakeTreeNode(element);
                    }


static void MakeTreeNode(AstNode node)
    {
        Console.WriteLine(GetNodeTitle(node));
        foreach (AstNode child in node.Children)
        {
            MakeTreeNode(child);
        }
    }

    static string GetNodeTitle(AstNode node)
    {
        StringBuilder b = new StringBuilder();
        b.Append(node.Role.ToString());
        b.Append(": ");
        b.Append(node.GetType().Name);
        bool hasProperties = false;
        foreach (PropertyInfo p in node.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
        {
            if (p.Name == "NodeType" || p.Name == "IsNull" || p.Name == "IsFrozen" || p.Name == "HasChildren")
                continue;
            if (p.PropertyType == typeof(string) || p.PropertyType.IsEnum || p.PropertyType == typeof(bool))
            {
                if (!hasProperties)
                {
                    hasProperties = true;
                    b.Append(" (");
                }
                else
                {
                    b.Append(", ");
                }
                b.Append(p.Name);
                b.Append(" = ");
                try
                {
                    object val = p.GetValue(node, null);
                    b.Append(val != null ? val.ToString() : "**null**");
                }
                catch (TargetInvocationException ex)
                {
                    b.Append("**" + ex.InnerException.GetType().Name + "**");
                }
            }
        }
        if (hasProperties)
            b.Append(")");
        return b.ToString() + "\n";
    }

I was wondering if there is a method in the NRefactory API that would get the documentation associated to a method in a C# piece of code.


Solution

  • I did find a method that will get me the documentation associated to a method in the NRefactory API. It is the "GetDocumentation" method which has two overloads

    • DocumentationComment GetDocumentation(IEntity entity);
    • DocumentationComment GetDocumentation(IUnresolvedEntity entity, IEntity resolvedEntity);

    Below is an example of usage

                    SyntaxTree tree = parser.Parse(line, "demo.cs");
    
                    var testClass = tree.Descendants.OfType<TypeDeclaration>().Single(x => x.Members == Method);
                    var testClassAttributes = testClass.Attributes.SelectMany(x => x.Attributes).ToArray();
    
                    List<Dictionary<string, object>> myList = new List<Dictionary<string, object>>();
    
                    string nombreControlador = null;
                    string rutaControlador = null;
                    string actionKeyPath = null;
                    string fullControllerPath = null;
                    int counter = 0;
    
                    CSharpUnresolvedFile file = tree.ToTypeSystem();
    
    
    
                    foreach (IUnresolvedTypeDefinition type in file.TopLevelTypeDefinitions)
                    {
                        nombreControlador = type.Name;
                        actionKeyPath = type.Fields.Skip(1).FirstOrDefault().ConstantValue.ToString();
                        fullControllerPath = type.Fields.First().ConstantValue.ToString();
                        rutaControlador = type.FullName;
                        foreach (IUnresolvedMethod method in type.Methods)
                        {
                            string documentation = file.GetDocumentation(method).Trim();
    
                            XDocument doc = XDocument.Parse("<documentation>" + documentation + "</documentation>");        
                            Dictionary<string, object> myDic = new Dictionary<string, object>();
                            Console.WriteLine(method.Name);
                            myDic.Add("MethodSignature", method.Name);
                            myDic.Add("MethodDescription", doc.Descendants().Select(e => (string)e.Element("summary")).FirstOrDefault());
                            myDic.Add("ActionKeyPath", actionKeyPath == null? "" : actionKeyPath);
                            myDic.Add("Counter", ++counter);
                            myDic.Add("FullControllerPath", fullControllerPath == null? "" : fullControllerPath);
                            myDic.Add("Route", method.Attributes == null ? "" : method.Attributes.Count <= 1 || method.Attributes.Skip(1) == null? "" : method.Attributes.SelectMany(a => a.);
                            myDic.Add("Verb", "");
                            myDic.Add("Input", "");
                            myDic.Add("Output", "");
                            myList.Add(myDic);
                        }
                    }
    

    I am using the 5.0 version of NRefactorize by the way. I remember reading somewhere that the version 5.0 includes comments in the Abstract Syntax Tree