public void DocumentFunction(Function function) { if (!this.functionNodes.ContainsKey(function.OriginalName)) { return; } var lineStart = function.LineNumberStart.ToString(); var lineEnd = function.LineNumberEnd.ToString(); var functions = this.functionNodes[function.OriginalName]; var node = functions.Find( f => f.Attribute("location").Value == function.TranslationUnit.FileName && (f.Attribute("lineno").Value == lineStart || f.Attribute("lineno").Value == lineEnd)); // HACK: functions in qglobal.h have weird additional definitions just for docs if ((node == null || node.Attribute("href") == null) && function.TranslationUnit.FileName == "qglobal.h") { node = functions.Find( c => c.Attribute("location").Value == function.TranslationUnit.FileName && c.Attribute("name").Value == function.OriginalName); } // HACK: some functions are "located" in a cpp, go figure... var @params = function.Parameters.Where(p => p.Kind == ParameterKind.Regular).ToList(); if ((node == null || node.Attribute("href") == null) && function.Signature != null) { var qualifiedOriginalName = function.GetQualifiedName(decl => decl.OriginalName, decl => { var @class = decl.OriginalNamespace as Class; return @class != null ? (@class.OriginalClass ?? @class) : decl.OriginalNamespace; }); var nodes = functions.Where(f => f.Attribute("fullname") != null && f.Attribute("fullname").Value == qualifiedOriginalName && f.Descendants("parameter").Count() == @params.Count).ToList(); if (nodes.Count == 0) { @params.RemoveAll(p => string.IsNullOrEmpty(p.OriginalName) && p.DefaultArgument != null); } nodes = functions.Where(f => f.Attribute("fullname") != null && f.Attribute("fullname").Value == qualifiedOriginalName && f.Descendants("parameter").Count() == @params.Count).ToList(); if (nodes.Count == 0) { var method = function as Method; if (method != null && !method.IsStatic && function.OriginalFunction == null) { return; } nodes = functions.Where(f => f.Attribute("name").Value == function.OriginalName && f.Descendants("parameter").Count() == @params.Count).ToList(); } if (nodes.Count == 1) { node = nodes[0]; } else { if (function.Signature.Contains('(')) { var startArgs = function.Signature.IndexOf('(') + 1; var signature = function.Signature; if (signature.Contains(": ")) { signature = signature.Substring(0, signature.IndexOf(": ", StringComparison.Ordinal)); } signature = signature.Substring(startArgs, signature.LastIndexOf(')') - startArgs); signature = this.regexSpaceBetweenArgs.Replace(this.regexArgName.Replace(signature, "$1$3$5"), " "); node = nodes.Find(f => string.Join(", ", f.Descendants("parameter").Select(d => d.Attribute("left").Value.Replace(" *", "*").Replace(" &", "&"))) == signature); } } } if (node != null && node.Attribute("href") != null) { var link = node.Attribute("href").Value.Split('#'); var file = link[0]; if (this.membersDocumentation.ContainsKey(file)) { var id = link[1].Split('-'); var key = EscapeId(function.IsAmbiguous && node.Attribute("access").Value == "private" ? id[0] : link[1]); if (this.membersDocumentation[file].ContainsKey(key)) { var docs = this.membersDocumentation[file][key]; var i = 0; // HACK: work around bugs of the type of https://bugreports.qt.io/browse/QTBUG-46148 if ((function.OperatorKind == CXXOperatorKind.Greater && function.Namespace.Name == "QLatin1String" && @params[0].Type.ToString() == "QLatin1String") || ((function.OriginalName == "flush" || function.OriginalName == "reset") && function.Namespace.Name == "QTextStream" && @params.Count > 0)) { docs = this.membersDocumentation[file][key + "-hack"]; } foreach (Match match in Regex.Matches(docs[0].InnerHtml, @"<i>\s*(.+?)\s*</i>")) { @params[i].Name = Helpers.SafeIdentifier(match.Groups[1].Value); i++; } // TODO: create links in the "See Also" section function.Comment = new RawComment { BriefText = StripTags(ConstructDocumentText(docs.Skip(1))) }; if (node.Attribute("status").Value == "obsolete") { AddObsoleteAttribute(function); } } } } }