Example #1
0
 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));
Example #2
0
        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());
        }
Example #5
0
        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);
        }
Example #7
0
        /// <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);
                    }
                }
            }
        }
Example #8
0
        /// <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);
            }
        }
Example #9
0
        /// <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);
        }
Example #12
0
 /// <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);
 }
Example #13
0
 /// <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)));
 }
Example #15
0
 public static T[] EnumerateDescendants <T>(this CsBase element, bool withAdditionalItems = true)
     where T : CsBase => ModelUtilities.EnumerateDescendants <T>(element, withAdditionalItems).ToArray();
Example #16
0
 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 })
Example #19
0
 private static string GetExternalDocCommentId(CsBase element)
 {
     return(element.CppElementName ?? element.QualifiedName);
 }
Example #20
0
 public CsNamespace(CsBase parentContainer, string nameSpace)
 {
     Name = nameSpace;
     Parent = parentContainer;
 }
Example #21
0
        /// <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();
            }
        }
Example #22
0
 /// <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);
Example #23
0
    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);
                }
            }
        }
    }
Example #24
0
 /// <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);
Example #25
0
 /// <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);
 }
Example #26
0
 /// <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);
 }
Example #28
0
 public static CsBase[] EnumerateDescendants(this CsBase element, bool withAdditionalItems = true) =>
 ModelUtilities.EnumerateDescendants(element, withAdditionalItems).ToArray();