public void ParseCompoundDefElement(XmlElement e)
        {
            Symbol s = new Symbol();
            s.id = e.GetAttribute("id");
            s.kind = e.GetAttribute("kind");
            s.visibilityLevel = ParseVisibilityLevel(e.GetAttribute("prot"));
            s.classMemberIndexTitle = s.name = GetXmlElementChildNodeValue(e, "compoundname");

            // The "author" section.
            XmlElement author = e.FirstGrandChildElementOfTypeAndAttribute("simplesect", "kind", "author");
            if (author != null)
            {
                s.author = author.InnerXml;
                author.ParentNode.RemoveChild(author);
            }

            s.briefDescription = GetXmlElementChildNodeValue(e, "briefdescription");
            s.inbodyDescription = GetXmlElementChildNodeValue(e, "inbodydescription");
            s.detailedDescription = GetXmlElementChildNodeValue(e, "detaileddescription");
            symbols[s.id] = s;
            symbolsByName[s.name] = s;

            ProcessDocGeneratorCommentDirectives(s);

            foreach(XmlElement child in e.ChildNodes)
            {
                if (child.Name == "sectiondef")
                    ParseSectionDefElement(s, child);
            }            
            // Also has the following members:
            // <collaborationgraph>
            // <location>
            // <listofallmembers>
            // <includes>
        }
        /// <summary>
        /// Goes through the given symbol and find all DocGenerator-style directives present in the comments
        /// and applies them. These directives are of form [foo].
        /// </summary>
        private void ProcessDocGeneratorCommentDirectives(Symbol s)
        {
//            string[] comments = s.Comments();
            string[] comments = new string[3] { s.briefDescription, s.detailedDescription, s.inbodyDescription };
            for (int i = 0; i < comments.Length; ++i)
            {
                comments[i] = comments[i].Trim();
                if (comments[i].EndsWith("<br/>"))
                    comments[i] = comments[i].Substring(0, comments[i].Length - 5);
                if (comments[i].EndsWith("<br />"))
                    comments[i] = comments[i].Substring(0, comments[i].Length - 6);
                comments[i] = comments[i].Trim();

                int endIdx;
                int startIndex = 0;
                while (startIndex < comments[i].Length)
                {
                    string directive = FindStringInBetween(comments[i], startIndex, "[", "]", out endIdx);
                    if (endIdx == -1)
                        break;

                    int directiveStartIndex = endIdx - directive.Length - 1;
                    directive = directive.Trim();
                    string[] st = directive.Split(':');
                    string directiveParam = "";
                    if (st.Length == 2)
                        directiveParam = st[1].Trim();

                    if (directive.ToLower().StartsWith("similaroverload") && directiveParam.Length > 0)
                    {
                        Symbol similarOverloadSymbol = s.parent.FindChildByName(directiveParam);
                        if (similarOverloadSymbol != null)
                        {
                            if (s.similarOverload == null)
                            {
                                s.similarOverload = similarOverloadSymbol;
                                similarOverloadSymbol.otherOverloads.Add(s);
                            }
                        }
                        else
                        {
//                            Console.WriteLine("Can't find similarOverload " + directiveParam + " for member " + s.FullQualifiedSymbolName());
                        }
                        comments[i] = CutDocGeneratorCommentDirective(comments[i], directiveStartIndex - 1, endIdx + 1 - directiveStartIndex);
                        startIndex = 0;

                        // Don't update startIndex since we deleted the "[]" block.
                    }
                    else if (directive.ToLower().StartsWith("indextitle") && directiveParam.Length > 0)
                    {
                        s.classMemberIndexTitle = directiveParam;
                        comments[i] = CutDocGeneratorCommentDirective(comments[i], directiveStartIndex - 1, endIdx + 1 - directiveStartIndex);
                        startIndex = 0;
                    }
                    else if (directive.ToLower().StartsWith("hideindex"))
                    {
                        s.classMemberIndexTitle = "";
                        comments[i] = CutDocGeneratorCommentDirective(comments[i], directiveStartIndex - 1, endIdx + 1 - directiveStartIndex);
                        startIndex = 0;
                    }
                    else if (directive.ToLower().StartsWith("category"))
                    {
                        s.documentationCategory = directiveParam;
                        comments[i] = CutDocGeneratorCommentDirective(comments[i], directiveStartIndex - 1, endIdx + 1 - directiveStartIndex);
                        startIndex = 0;
                    }
                    else if (directive.ToLower().StartsWith("groupsyntax"))
                    {
                        s.groupSyntax = true;
                        comments[i] = CutDocGeneratorCommentDirective(comments[i], directiveStartIndex - 1, endIdx + 1 - directiveStartIndex);
                        startIndex = 0;
                    }
                    else
                    {
                        startIndex = endIdx;
                    }
                }
            }
            s.briefDescription = comments[0];
            s.detailedDescription = comments[1];
            s.inbodyDescription = comments[2];
        }
        public void ParseSectionDefElement(Symbol parent, XmlElement e)
        {
            foreach(XmlElement child in e.ChildNodes)
            {
                if (child.Name == "memberdef")
                {
                    Symbol member = new Symbol();
                    member.parent = parent;
                    member.id = child.GetAttribute("id");
                    member.kind = child.GetAttribute("kind");
                    member.visibilityLevel = ParseVisibilityLevel(child.GetAttribute("prot"));
                    member.isStatic = (child.GetAttribute("static") == "yes");
                    member.isConst = (child.GetAttribute("const") == "yes");
                    member.isMutable = (child.GetAttribute("mutable") == "yes");
                    member.isExplicit = (child.GetAttribute("explicit") == "yes");
                    member.virtualness = ParseVirtualness(child.GetAttribute("virt"));
                    member.type = GetXmlElementChildNodeValue(child, "type", true);
                    member.fullDefinition = GetXmlElementChildNodeValue(child, "definition");
                    member.argList = GetXmlElementChildNodeValue(child, "argsstring");

                    // Sanitate return type of certain MathGeoLib constructs
                    if (member.kind == "function")
                    {
                        member.type = member.type.Replace("CONST_WIN32", "");
                        member.type = member.type.Replace("MUST_USE_RESULT", "");
                    }

                    member.classMemberIndexTitle = member.name = GetXmlElementChildNodeValue(child, "name");
                    if (member.name.StartsWith("@"))
                        continue; // Doxygen creates items with names starting with '@' at least for unnamed unions, ignore those altogether.
                    symbols[member.id] = member;
                    //symbolsByName[member.name] = member;
                    parent.children.Add(member);

                    // Function parameters.
                    foreach(XmlElement param in child.ChildNodes.OfType<XmlElement>())
                        if (param.Name == "param")
                        {
                            Parameter p = new Parameter();
                            if (member.kind == "define") // This is a #define macro.
                            {
                                p.type = "";
                                p.name = GetXmlElementChildNodeValue(param, "defname");
                            }
                            else // This is a real function
                            {
                                p.type = GetXmlElementChildNodeValue(param, "type", true);
                                p.name = GetXmlElementChildNodeValue(param, "declname");
                                p.defaultValue = GetXmlElementChildNodeValue(param, "defval", true);
                            }
                            member.parameters.Add(p);
                        }

                    // Enum special handling
                    if (member.kind == "enum")
                    {
                        int lastEnumInitializer = -1;

                        foreach (XmlElement value in child.ChildNodes.OfType<XmlElement>())
                        {
                            if (value.Name == "enumvalue")
                            {
                                Symbol valueSymbol = new Symbol();
                                valueSymbol.parent = member;
                                valueSymbol.id = value.GetAttribute("id");
                                valueSymbol.name = GetXmlElementChildNodeValue(value, "name", true);
                                valueSymbol.kind = "enumvalue";
                                valueSymbol.value = GetXmlElementChildNodeValue(value, "initializer", true).Replace("= ", "");
                                if (valueSymbol.value.Length == 0)
                                {
                                    ++lastEnumInitializer;
                                    valueSymbol.value = lastEnumInitializer.ToString();
                                }
                                else
                                    Int32.TryParse(valueSymbol.value, out lastEnumInitializer);
                                member.children.Add(valueSymbol);
                            }
                        }
                        enumsByName[member.name] = member;
                    }

                    // If this is a #define macro, get the macro body code.
                    if (member.kind == "define")
                    {
                        member.macroBody = GetXmlElementChildNodeValue(child, "initializer");
                        // Create the argList from scratch, because it is not present in the xml in same form than for functions.
                        member.argList = member.ArgStringWithoutTypes();
                    }

                    // Function parameter comments.
                    List<XmlElement> parameters = child.AllGrandChildElementsOfTypeAndAttribute("parameterlist", "kind", "param");
                    if (parameters != null && parameters.Count > 0)
                    {
                        foreach (XmlElement paramNode in parameters.OfType<XmlElement>())
                        {
                            foreach (XmlElement param in paramNode.ChildNodes.OfType<XmlElement>())
                            {
                                if (param.Name == "parameteritem")
                                {
                                    string paramName = param.FirstChildElementOfType("parameternamelist").FirstChildElementOfType("parametername").InnerText.Trim();
                                    Parameter p = member.FindParamByName(paramName);
                                    if (p != null)
                                        p.comment = param.FirstChildElementOfType("parameterdescription").InnerText;
                                }
                            }
                            // Remove the parameterlist from the detailed description node so that it won't appear in the 'detailedDescription' documentation string.
                            // The detailed description is created manually.
                            paramNode.ParentNode.RemoveChild(paramNode);
                        }
                    }

                    // TODOs ^ BUGs 
                    List<XmlElement> xrefsects = child.AllGrandChildElementsOfType("xrefsect");
                    if (xrefsects != null)
                    {
                        foreach (XmlElement elem in xrefsects)
                        {
                            if (GetXmlElementChildNodeValue(elem, "xreftitle") == "Todo")
                                member.todos.Add(GetXmlElementChildNodeValue(elem, "xrefdescription"));
                            if (GetXmlElementChildNodeValue(elem, "xreftitle") == "Bug")
                                member.bugs.Add(GetXmlElementChildNodeValue(elem, "xrefdescription"));
                            elem.ParentNode.RemoveChild(elem);
                        }
                    }

                    // @notes.
                    List<XmlElement> notesects = child.AllGrandChildElementsOfTypeAndAttribute("simplesect", "kind", "note");
                    if (notesects != null)
                    {
                        foreach (XmlElement elem in notesects)
                        {
                            member.notes.Add(elem.InnerText);
                            elem.ParentNode.RemoveChild(elem);
                        }
                    }

                    // Function return value.
                    XmlElement retVal = child.FirstGrandChildElementOfTypeAndAttribute("simplesect", "kind", "return");
                    if (retVal != null)
                    {
                        member.returnComment = retVal.InnerText;
                        retVal.ParentNode.RemoveChild(retVal);
                    }

                    // The "see also" section.
                    XmlElement see = child.FirstGrandChildElementOfTypeAndAttribute("simplesect", "kind", "see");
                    if (see != null)
                    {
                        member.seeAlsoDocumentation = see.InnerXml;
                        see.ParentNode.RemoveChild(see);
                    }

                    member.briefDescription = GetXmlElementChildNodeValue(child, "briefdescription").Trim();
                    member.inbodyDescription = GetXmlElementChildNodeValue(child, "inbodydescription").Trim();
                    member.detailedDescription = GetXmlElementChildNodeValue(child, "detaileddescription").Trim();
                    XmlElement loc = child.FirstChildElementOfType("location");
                    if (loc != null)
                    {
                        member.sourceFilename = loc.GetAttribute("bodyfile");
                        int.TryParse(loc.GetAttribute("bodystart"), out member.sourceFileStartLine);
                        int.TryParse(loc.GetAttribute("bodyend"), out member.sourceFileEndLine);
                        if (member.sourceFileEndLine == -1)
                            member.sourceFileEndLine = member.sourceFileStartLine;
                    }
                    ProcessDocGeneratorCommentDirectives(member);

                    ///\todo Add location.
                }
            }            
        }
 void GroupSimilarOverloads(Symbol s)
 {
     for(int i = 0; i < s.children.Count; ++i)
         for(int j = i+1; j < s.children.Count; ++j)
         {
             Symbol master = s.children[i];
             Symbol child = s.children[j];
             if (master.similarOverload == null && child.similarOverload == null && child.otherOverloads.Count == 0)
             {
                 if (master.name == child.name)
                 {
                     if (child.Comments().Length == 0 || child.groupSyntax)
                     {
                         child.similarOverload = master;
                         master.otherOverloads.Add(child);
                     }
                     else
                         break;
                 }
             }
         }
 }