private static NamespaceDeclarationSyntax GenerateNamespaceDeclaration <T>( CsBase csNamespace, IEnumerable <T> elements, IMultiCodeGenerator <T, MemberDeclarationSyntax> generator ) where T : CsBase => NamespaceDeclaration( ParseName(csNamespace.Name), default, default, List(elements.OrderBy(element => element.Name).SelectMany(generator.GenerateCode)) ).WithLeadingTrivia(Comment(AutoGeneratedCommentText));
public static IEnumerable <CsBase> EnumerateDescendants(this CsBase element) { yield return(element); foreach (var descendant in element.Items.SelectMany(EnumerateDescendants)) { yield return(descendant); } }
private SyntaxTriviaList GenerateDocumentationTrivia(CsBase csElement) { var docItems = DocumentationLinker.GetDocItems(ExternalDocReader, csElement); StringBuilder builder = new(); foreach (var docItem in docItems) { builder.AppendLine($"/// {docItem}"); } builder.AppendLine(); return(ParseLeadingTrivia(builder.ToString())); }
protected DocumentationCommentTriviaSyntax GenerateDocumentationTrivia(CsBase csElement) { var docItems = docAggregator.GetDocItems(docReader, csElement); var builder = new StringBuilder(); foreach (var docItem in docItems) { builder.AppendLine($"/// {docItem}"); } builder.AppendLine(); var tree = CSharpSyntaxTree.ParseText(builder.ToString()); return((DocumentationCommentTriviaSyntax)tree.GetCompilationUnitRoot().EndOfFileToken.LeadingTrivia[0].GetStructure()); }
public static IEnumerable <CsBase> EnumerateDescendants(this CsBase element, bool withAdditionalItems = true) { yield return(element); IEnumerable <CsBase> items = element.Items; if (withAdditionalItems) { items = items.Concat(element.AdditionalItems); } foreach (var descendant in items.SelectMany(x => EnumerateDescendants(x, withAdditionalItems))) { yield return(descendant); } }
public string GetDocumentWithExternalComments(CsBase element) { string externalDocCommentId = GetExternalDocCommentId(element); foreach (var document in ExternalCommentsDocuments) { foreach (XmlNode node in document.Value.ChildNodes) { if (node.Name == "comment" && node.Attributes["id"].Value == externalDocCommentId) { return(document.Key); } } } return(null); }
/// <summary> /// Tries to attach declared constants to this C# type. /// </summary> /// <param name="csType">The C# type</param> public void AttachConstants(CsBase csType) { foreach (var innerElement in csType.Items) { AttachConstants(innerElement); } foreach (var keyValuePair in _mapConstantToCSharpType) { if (csType.QualifiedName == keyValuePair.Key) { foreach (var constantDef in keyValuePair.Value) { csType.Add(constantDef); } } } }
/// <summary> /// Tries to attach declared constants to this C# type. /// </summary> /// <param name="csType">The C# type</param> public void AttachConstants(CsBase csType) { foreach (var innerElement in csType.Items) { AttachConstants(innerElement); } var qualifiedName = csType.QualifiedName; if (!_mapConstantToCSharpType.TryGetValue(qualifiedName, out var list)) { return; } foreach (var constantDef in list) { csType.Add(constantDef); } }
/// <summary> /// Processes the specified C# element to complete the mapping process between the C++ and C# element. /// </summary> /// <param name="csElement">The C# element.</param> public override void Process(CsBase csElement) { try { var csMethod = (CsMethod)csElement; Logger.PushContext("Method {0}", csMethod.CppElement); Process(csMethod); if (csMethod is CsFunction) csMethod.Visibility = csMethod.Visibility | Visibility.Static; RegisterNativeInteropSignature(csMethod); } finally { Logger.PopContext(); } }
public static string GetSingleDoc(this IDocumentationLinker aggregator, CsBase element) { var description = element.Description; if (RegexLinkStart.Match(description).Success) { description = RegexLinkStart.Replace(description, "$1"); } description = RegexSpaceBegin.Replace(description, "$1"); description = RegexLink.Replace(description, aggregator.ReplaceCRefReferences); var docItems = new StringBuilder(); foreach (var line in description.Split('\n')) { docItems.Append(line); } return(docItems.ToString()); }
public static IEnumerable <string> GetDocItems(this IDocumentationLinker aggregator, ExternalDocCommentsReader reader, CsBase element) { var docItems = new List <string>(); var externalCommentsPath = reader.GetDocumentWithExternalComments(element); if (externalCommentsPath == null) { var description = element.Description; var remarks = element.Remarks; description = RegexSpaceBegin.Replace(description, "$1"); description = RegexLink.Replace(description, aggregator.ReplaceCRefReferences); // evaluator => "<see cref=\"$1\"/>" docItems.Add("<summary>"); docItems.AddRange(description.Split('\n')); docItems.Add("</summary>"); element.FillDocItems(docItems, aggregator); if (!string.IsNullOrEmpty(remarks)) { remarks = RegexSpaceBegin.Replace(remarks, "$1"); remarks = RegexLink.Replace(remarks, aggregator.ReplaceCRefReferences); docItems.Add("<remarks>"); docItems.AddRange(remarks.Split('\n')); docItems.Add("</remarks>"); } } else { docItems.Add($"<include file='{externalCommentsPath}' path=\"{ExternalDocCommentsReader.GetCodeCommentsXPath(element)}/*\" />"); } if (element.CppElementName != null) { if (element.DocId != null) { docItems.Add("<doc-id>" + EscapeXml(element.DocId) + "</doc-id>"); } docItems.Add("<unmanaged>" + EscapeXml(element.DocUnmanagedName) + "</unmanaged>"); docItems.Add("<unmanaged-short>" + EscapeXml(element.DocUnmanagedShortName) + "</unmanaged-short>"); } return(docItems); }
/// <summary> /// Processes the specified C# element to complete the mapping process between the C++ and C# element. /// </summary> /// <param name="csElement">The cs element.</param> public override void Process(CsBase csElement) { Process((CsEnum)csElement); }
/// <summary> /// Processes the specified C# element to complete the mapping process between the C++ and C# element. /// </summary> /// <param name="csElement">The C# element.</param> public override void Process(CsBase csElement) { Process((CsEnum)csElement); }
protected TMember AddDocumentationTrivia <TMember>(TMember member, CsBase csElement) where TMember : MemberDeclarationSyntax { return(member.WithLeadingTrivia(GenerateDocumentationTrivia(csElement))); }
public static T[] EnumerateDescendants <T>(this CsBase element, bool withAdditionalItems = true) where T : CsBase => ModelUtilities.EnumerateDescendants <T>(element, withAdditionalItems).ToArray();
public static string GetCodeCommentsXPath(CsBase element) { return($"/comments/comment[@id='{GetExternalDocCommentId(element)}']"); }
/// <summary> /// Processes the specified C# element to complete the mapping process between the C++ and C# element. /// </summary> /// <param name="csElement">The C# element.</param> public override void Process(CsBase csElement) { Process((CsInterface)csElement); }
public IReadOnlyList <T> GetList(CsBase container) { if (list is { Invalid : true })
private static string GetExternalDocCommentId(CsBase element) { return(element.CppElementName ?? element.QualifiedName); }
public CsNamespace(CsBase parentContainer, string nameSpace) { Name = nameSpace; Parent = parentContainer; }
/// <summary> /// Processes the specified C# element to complete the mapping process between the C++ and C# element. /// </summary> /// <param name="csElement">The C# element.</param> public abstract void Process(CsBase csElement);
private static async Task <IDocItem?> DocumentElement(IDocProvider?docProvider, DocItemCache cache, CsBase element, DocumentationContext context, bool documentInnerElements, string?name) { var docName = name ?? element.CppElementName; if (string.IsNullOrEmpty(docName)) { return(null); } docName = docName.Trim(); if (string.IsNullOrEmpty(docName)) { return(null); } var cacheEntry = cache.Find(docName); var docItem = cacheEntry ?? await QueryDocumentationProvider(); if (docItem == null) { return(null); } element.DocId = docItem.ShortId; element.Description = docItem.Summary; element.Remarks = docItem.Remarks; docItem.Names.Add(docName); if (cacheEntry == null) { cache.Add(docItem); } if (element.Items.Count == 0) { return(docItem); } if (documentInnerElements) { DocumentInnerElements(element.Items, docItem); } return(docItem); async Task <IDocItem?> QueryDocumentationProvider() { if (docProvider == null) { return(null); } Lazy <string> docProviderName = new( () => { try { var friendlyName = docProvider.UserFriendlyName; return(string.IsNullOrWhiteSpace(friendlyName) ? FullName() : friendlyName); } catch { return(FullName()); } string FullName() { var type = docProvider.GetType(); var name = type.FullName; return(string.IsNullOrEmpty(name) ? type.Name : name !); } }, LazyThreadSafetyMode.None ); List <Exception> exceptions = new(3); var(backoff, backoffIndex, nextDelay) = GenerateBackoff(TimeSpan.Zero); try { for (uint retry = 0; retry <= 5; retry++) { if (retry != 0) { TimeSpan delay; if (nextDelay.HasValue) { delay = nextDelay.Value; } else { // TODO: fix the bug and remove this hack if (backoffIndex >= 5) { context.Logger.Message( $"SharpGen internal invalid state on delay: backoffIndex == {backoffIndex}" ); if (Debugger.IsAttached) { Debugger.Break(); } backoffIndex = 0; } delay = backoff[backoffIndex++]; } if (delay > TimeSpan.Zero) { await Task.Delay(delay); } nextDelay = null; } try { var result = await docProvider.FindDocumentationAsync(docName, context); switch (result) { case null: throw new ArgumentNullException( nameof(result), $"Unexpected null {nameof(IFindDocumentationResult)}" ); case FindDocumentationResultFailure resultFailure: { var retryDelay = resultFailure.RetryDelay; if (retryDelay == TimeSpan.MaxValue) { return(null); } if (retryDelay <= TimeSpan.Zero) { nextDelay = TimeSpan.Zero; } // TODO: fix the bug and remove this hack if (backoffIndex >= 5) { context.Logger.Message( $"SharpGen internal invalid state on reschedule: backoffIndex = {backoffIndex}" ); if (Debugger.IsAttached) { Debugger.Break(); } (backoff, backoffIndex, nextDelay) = GenerateBackoff(retryDelay); } nextDelay = backoff[backoffIndex++]; if (nextDelay < retryDelay) { (backoff, backoffIndex, nextDelay) = GenerateBackoff(retryDelay); } break; } case FindDocumentationResultSuccess resultSuccess: return(resultSuccess.Item); // TODO: check if the item is empty (therefore, useless) default: throw new ArgumentOutOfRangeException( nameof(result), $"Unexpected {nameof(IFindDocumentationResult)}: {result.GetType().FullName}" ); } } catch (Exception e) { e.Data["SDK:" + nameof(docProvider)] = docProvider; e.Data["SDK:" + nameof(docName)] = docName; e.Data["SDK:" + nameof(context)] = context; e.Data["SDK:" + nameof(retry)] = retry; e.Data["SDK:" + nameof(backoffIndex)] = backoffIndex; e.Data["SDK:" + nameof(exceptions) + ".Count"] = exceptions.Count; exceptions.Add(e); // We should retry less when it's due to unhandled exception. // So in exception case we step twice in retry count on each iteration. retry++; } } context.Logger.Message($"{docProviderName.Value} extension failed to find documentation for \"{docName}\""); return(null); } finally { if (exceptions.Count > 0) { var failure = new DocumentationQueryFailure(docName) { Exceptions = exceptions, FailedProviderName = docProviderName.Value, TreatProviderFailuresAsErrors = docProvider.TreatFailuresAsErrors }; context.Failures.Add(failure); } } } }
/// <summary> /// Processes the specified C# element to complete the mapping process between the C++ and C# element. /// </summary> /// <param name="csElement">The C# element.</param> public override void Process(CsBase csElement) { Process((CsInterface) csElement); }
/// <summary> /// Processes the specified C# element to complete the mapping process between the C++ and C# element. /// </summary> /// <param name="csElement">The cs element.</param> public override void Process(CsBase csElement) { Process((CsStruct)csElement); }
/// <summary> /// Processes the specified C# element to complete the mapping process between the C++ and C# element. /// </summary> /// <param name="csElement">The C# element.</param> public override void Process(CsBase csElement) { Process((CsStruct)csElement); }
public static CsBase[] EnumerateDescendants(this CsBase element, bool withAdditionalItems = true) => ModelUtilities.EnumerateDescendants(element, withAdditionalItems).ToArray();