/// <inheritdoc/>
        protected override void HandleXmlElement(SyntaxNodeAnalysisContext context, DocumentationCommentTriviaSyntax documentation, XmlNodeSyntax syntax, XElement completeDocumentation, Location[] diagnosticLocations)
        {
            if (syntax == null)
            {
                return;
            }

            if (completeDocumentation != null)
            {
                XElement summaryNode = completeDocumentation.Nodes().OfType<XElement>().FirstOrDefault(element => element.Name == XmlCommentHelper.SummaryXmlTag);
                if (summaryNode == null)
                {
                    // Handled by SA1604
                    return;
                }

                if (!XmlCommentHelper.IsConsideredEmpty(summaryNode))
                {
                    return;
                }
            }
            else
            {
                if (!XmlCommentHelper.IsConsideredEmpty(syntax))
                {
                    return;
                }
            }

            foreach (var location in diagnosticLocations)
            {
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));
            }
        }
        /// <inheritdoc/>
        protected override void HandleXmlElement(SyntaxNodeAnalysisContext context, DocumentationCommentTriviaSyntax documentation, XmlNodeSyntax syntax, XElement completeDocumentation, Location[] diagnosticLocations)
        {
            if (completeDocumentation != null)
            {
                // We are working with an <include> element
                if (completeDocumentation.Nodes().OfType<XElement>().Any(element => element.Name == XmlCommentHelper.SummaryXmlTag))
                {
                    return;
                }

                if (completeDocumentation.Nodes().OfType<XElement>().Any(element => element.Name == XmlCommentHelper.InheritdocXmlTag))
                {
                    // Ignore nodes with an <inheritdoc/> tag in the included XML.
                    return;
                }
            }
            else
            {
                if (syntax != null)
                {
                    return;
                }

                if (documentation?.Content.GetFirstXmlElement(XmlCommentHelper.InheritdocXmlTag) != null)
                {
                    // Ignore nodes with an <inheritdoc/> tag.
                    return;
                }
            }

            foreach (var location in diagnosticLocations)
            {
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));
            }
        }
コード例 #3
0
        private void ClassifyDocumentationComment(DocumentationCommentTriviaSyntax documentationComment)
        {
            if (!_textSpan.OverlapsWith(documentationComment.Span))
            {
                return;
            }

            foreach (var xmlNode in documentationComment.Content)
            {
                var childFullSpan = xmlNode.FullSpan;
                if (childFullSpan.Start > _textSpan.End)
                {
                    return;
                }
                else if (childFullSpan.End < _textSpan.Start)
                {
                    continue;
                }

                ClassifyXmlNode(xmlNode);
            }

            // NOTE: the "EndOfComment" token is a special, zero width token.  However, if it's a multi-line xml doc comment
            // the final '*/" will be leading exterior trivia on it.
            ClassifyXmlTrivia(documentationComment.EndOfComment.LeadingTrivia);
        }
        private static IEnumerable<SyntaxNode> GetAllNodesToRemove(IEnumerable<Tuple<ParameterSyntax, Tuple<XmlElementSyntax, XmlNameAttributeSyntax>>> paramterWithDocParameter, DocumentationCommentTriviaSyntax documentationNode)
        {
            var nodesToRemove = paramterWithDocParameter.Where(p => p.Item1 == null).Select(x => x.Item2.Item1).ToList();

            var xmlTextNodesToRemove = documentationNode.Content.OfType<XmlTextSyntax>()
                .Join(nodesToRemove, textNode => textNode.FullSpan.End, tagNode => tagNode.FullSpan.Start, (textNode, tagNode) => textNode);

            var allNodesToRemove = nodesToRemove.Cast<SyntaxNode>().Union(xmlTextNodesToRemove);
            return allNodesToRemove;
        }
コード例 #5
0
 private static MethodDeclarationSyntax GetMethodFromXmlDocumentation(DocumentationCommentTriviaSyntax doc)
 {
     var tokenParent = doc.ParentTrivia.Token.Parent;
     var method = tokenParent as MethodDeclarationSyntax;
     if (method == null)
     {
         var attributeList = tokenParent as AttributeListSyntax;
         if (attributeList == null) return null;
         method = attributeList.Parent as MethodDeclarationSyntax;
     }
     return method;
 }
コード例 #6
0
        protected static IEnumerable<Tuple<ParameterSyntax, Tuple<XmlElementSyntax, XmlNameAttributeSyntax>>> GetMethodParametersWithDocParameters(MethodDeclarationSyntax method, DocumentationCommentTriviaSyntax documentationNode)
        {
            var methodParameters = method.ParameterList.Parameters;

            var xElementsWitAttrs = documentationNode.Content.OfType<XmlElementSyntax>()
                                    .Where(xEle => xEle.StartTag.Name.LocalName.ValueText == "param")
                                    .SelectMany(xEle => xEle.StartTag.Attributes, (xEle, attr) => new Tuple<XmlElementSyntax, XmlNameAttributeSyntax>(xEle, (XmlNameAttributeSyntax)attr));

            var keys = methodParameters.Select(parameter => parameter.Identifier.ValueText)
                .Union(xElementsWitAttrs.Select(x => x.Item2.Identifier.Identifier.ValueText))
                .ToImmutableHashSet();

            return (from key in keys
                    let Parameter = methodParameters.FirstOrDefault(p => p.Identifier.ValueText == key)
                    let DocParameter = xElementsWitAttrs.FirstOrDefault(p => p.Item2.Identifier.Identifier.ValueText == key)
                    select new Tuple<ParameterSyntax, Tuple<XmlElementSyntax, XmlNameAttributeSyntax>>(Parameter, DocParameter));
        }
            /// <summary>
            /// Given a DocumentationCommentTriviaSyntax, return the full text, but with
            /// documentation comment IDs substituted into crefs.
            /// </summary>
            /// <remarks>
            /// Still has all of the comment punctuation (///, /**, etc).
            /// </remarks>
            public static string GetSubstitutedText(
                CSharpCompilation compilation,
                DiagnosticBag diagnostics,
                Symbol symbol,
                DocumentationCommentTriviaSyntax trivia,
                ArrayBuilder<CSharpSyntaxNode> includeElementNodes,
                ref HashSet<ParameterSymbol> documentedParameters,
                ref HashSet<TypeParameterSymbol> documentedTypeParameters)
            {
                PooledStringBuilder pooled = PooledStringBuilder.GetInstance();
                using (StringWriter writer = new StringWriter(pooled.Builder, CultureInfo.InvariantCulture))
                {
                    DocumentationCommentWalker walker = new DocumentationCommentWalker(compilation, diagnostics, symbol, writer, includeElementNodes, documentedParameters, documentedTypeParameters);
                    walker.Visit(trivia);

                    // Copy back out in case they have been initialized.
                    documentedParameters = walker._documentedParameters;
                    documentedTypeParameters = walker._documentedTypeParameters;
                }
                return pooled.ToStringAndFree();
            }
コード例 #8
0
 private void RemoveExistingTags(DocumentationCommentTriviaSyntax parentTrivia, ISet<string> names, Func<XmlElementSyntax, string> selector)
 {
     if (parentTrivia != null)
     {
         foreach (var node in parentTrivia.Content)
         {
             var element = node as XmlElementSyntax;
             if (element != null)
             {
                 names.Remove(selector(element));
             }
         }
     }
 }
コード例 #9
0
		private IEnumerable<CompletionData> GetTagsForSymbol(CompletionEngine engine, ISymbol symbol, TextSpan filterSpan, DocumentationCommentTriviaSyntax trivia, SyntaxToken token)
		{
			if (symbol is IMethodSymbol)
			{
				return GetTagsForMethod(engine, (IMethodSymbol)symbol, filterSpan, trivia, token);
			}

			if (symbol is IPropertySymbol)
			{
				return GetTagsForProperty(engine, (IPropertySymbol)symbol, filterSpan, trivia);
			}

			if (symbol is INamedTypeSymbol)
			{
				return GetTagsForType(engine, (INamedTypeSymbol)symbol, filterSpan, trivia);
			}

			return SpecializedCollections.EmptyEnumerable<CompletionData>();
		}
コード例 #10
0
        private IEnumerable<CompletionItem> GetTagsForMethod(IMethodSymbol symbol, DocumentationCommentTriviaSyntax trivia)
        {
            var items = new List<CompletionItem>();

            var parameters = symbol.GetParameters().Select(p => p.Name).ToSet();
            var typeParameters = symbol.TypeParameters.Select(t => t.Name).ToSet();

            RemoveExistingTags(trivia, parameters, x => AttributeSelector(x, ParamTagName));
            RemoveExistingTags(trivia, typeParameters, x => AttributeSelector(x, TypeParamTagName));

            items.AddRange(parameters.Select(p => CreateCompletionItem(FormatParameter(ParamTagName, p))));
            items.AddRange(typeParameters.Select(t => CreateCompletionItem(FormatParameter(TypeParamTagName, t))));

            // Provide a return completion item in case the function returns something
            var returns = true;

            foreach (var node in trivia.Content)
            {
                var element = node as XmlElementSyntax;
                if (element != null && !element.StartTag.IsMissing && !element.EndTag.IsMissing)
                {
                    var startTag = element.StartTag;

                    if (startTag.Name.LocalName.ValueText == ReturnsTagName)
                    {
                        returns = false;
                        break;
                    }
                }
            }

            if (returns && !symbol.ReturnsVoid)
            {
                items.Add(CreateCompletionItem(ReturnsTagName));
            }

            return items;
        }
コード例 #11
0
        private async Task <Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
        {
            var documentRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            SyntaxNode syntax = documentRoot.FindNode(diagnostic.Location.SourceSpan);

            if (syntax == null)
            {
                return(document);
            }

            PropertyDeclarationSyntax propertyDeclarationSyntax = syntax.FirstAncestorOrSelf <PropertyDeclarationSyntax>();

            if (propertyDeclarationSyntax == null)
            {
                return(document);
            }

            DocumentationCommentTriviaSyntax documentationComment = propertyDeclarationSyntax.GetDocumentationCommentTriviaSyntax();

            if (documentationComment == null)
            {
                return(document);
            }

            if (!(documentationComment.Content.GetFirstXmlElement(XmlCommentHelper.SummaryXmlTag) is XmlElementSyntax summaryElement))
            {
                return(document);
            }

            SyntaxList <XmlNodeSyntax> summaryContent = summaryElement.Content;

            if (!this.TryRemoveSummaryPrefix(ref summaryContent, "Gets or sets "))
            {
                if (!this.TryRemoveSummaryPrefix(ref summaryContent, "Gets "))
                {
                    this.TryRemoveSummaryPrefix(ref summaryContent, "Sets ");
                }
            }

            SyntaxList <XmlNodeSyntax> content = summaryContent.WithoutFirstAndLastNewlines();

            if (!string.IsNullOrWhiteSpace(content.ToFullString()))
            {
                // wrap the content in a <placeholder> element for review
                content = XmlSyntaxFactory.List(XmlSyntaxFactory.PlaceholderElement(content));
            }

            string newLineText = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp);

            XmlElementSyntax valueElement = XmlSyntaxFactory.MultiLineElement(XmlCommentHelper.ValueXmlTag, newLineText, content);

            XmlNodeSyntax leadingNewLine = XmlSyntaxFactory.NewLine(newLineText);

            // HACK: The formatter isn't working when contents are added to an existing documentation comment, so we
            // manually apply the indentation from the last line of the existing comment to each new line of the
            // generated content.
            SyntaxTrivia exteriorTrivia = GetLastDocumentationCommentExteriorTrivia(documentationComment);

            if (!exteriorTrivia.Token.IsMissing)
            {
                leadingNewLine = leadingNewLine.ReplaceExteriorTrivia(exteriorTrivia);
                valueElement   = valueElement.ReplaceExteriorTrivia(exteriorTrivia);
            }

            // Try to replace an existing <value> element if the comment contains one. Otherwise, add it as a new element.
            SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            SyntaxNode    newRoot;
            XmlNodeSyntax existingValue = documentationComment.Content.GetFirstXmlElement(XmlCommentHelper.ValueXmlTag);

            if (existingValue != null)
            {
                newRoot = root.ReplaceNode(existingValue, valueElement);
            }
            else
            {
                DocumentationCommentTriviaSyntax newDocumentationComment = documentationComment.WithContent(
                    documentationComment.Content.InsertRange(
                        documentationComment.Content.Count - 1,
                        XmlSyntaxFactory.List(leadingNewLine, valueElement)));

                newRoot = root.ReplaceNode(documentationComment, newDocumentationComment);
            }

            return(document.WithSyntaxRoot(newRoot));
        }
コード例 #12
0
        private IEnumerable <CompletionData> GetTagsForType(CompletionEngine engine, INamedTypeSymbol symbol, TextSpan filterSpan, DocumentationCommentTriviaSyntax trivia)
        {
            var items = new List <CompletionData>();

            var typeParameters = symbol.TypeParameters.Select(p => p.Name).ToSet();

            RemoveExistingTags(trivia, typeParameters, x => AttributeSelector(x, "typeparam"));

            items.AddRange(typeParameters.Select(t => engine.Factory.CreateXmlDocCompletionData(
                                                     this,
                                                     FormatParameter("typeparam", t))));
            return(items);
        }
コード例 #13
0
        //public override void VisitDelegateDeclaration(DelegateDeclarationSyntax node)
        //{
        //    base.VisitDelegateDeclaration(node);
        //}

        //public override void VisitDestructorDeclaration(DestructorDeclarationSyntax node)
        //{
        //    base.VisitDestructorDeclaration(node);
        //}

        //public override void VisitDiscardDesignation(DiscardDesignationSyntax node)
        //{
        //    base.VisitDiscardDesignation(node);
        //}

        public override void VisitDocumentationCommentTrivia(DocumentationCommentTriviaSyntax node)
        {
            Debug.Fail(node.ToString());
            base.VisitDocumentationCommentTrivia(node);
        }
コード例 #14
0
 public ParsedType(NamespaceDeclarationSyntax node, DocumentationCommentTriviaSyntax documentation) : base(documentation)
 {
     _namespaceType = node;
 }
        /// <summary>
        /// Add documentation for the property.
        /// </summary>
        /// <param name="context">the code fix context.</param>
        /// <param name="root">the root syntax node.</param>
        /// <param name="methodDeclaration">the property declaration containing invalid documentation.</param>
        /// <param name="documentComment">the existing comment.</param>
        /// <returns>the correct code.</returns>
        private Task<Document> AddDocumentationAsync(
            CodeFixContext context,
            SyntaxNode root,
            MethodDeclarationSyntax methodDeclaration,
            DocumentationCommentTriviaSyntax documentComment)
        {
            var summary = this._commentNodeFactory.GetExistingSummaryCommentText(documentComment)
                          ?? this._commentNodeFactory.CreateCommentSummaryText(methodDeclaration);
            var @class = methodDeclaration.Parent as ClassDeclarationSyntax;
            var first = @class?.DescendantNodes().FirstOrDefault() == methodDeclaration;

            var parameters = this._commentNodeFactory.CreateParameters(methodDeclaration, documentComment);
            var typeParameters = this._commentNodeFactory.CreateTypeParameters(methodDeclaration, documentComment);

            var @return = this._commentNodeFactory.CreateReturnValueDocumentation(methodDeclaration, documentComment);
            var returns = @return == null
                ? new XmlElementSyntax[] { }
                : new[] { @return };
            var summaryPlusParameters = new XmlNodeSyntax[] { summary }
                .Concat(parameters)
                .Concat(returns)
                .Concat(typeParameters)
                .ToArray();

            var comment = this._commentNodeFactory
                .CreateDocumentComment(summaryPlusParameters)
                .AddLeadingEndOfLineTriviaFrom(methodDeclaration.GetLeadingTrivia());

            var trivia = SyntaxFactory.Trivia(comment);
            var methodTrivia = first
                   ? methodDeclaration.WithLeadingTrivia(trivia)
                   : methodDeclaration.WithLeadingTrivia(SyntaxFactory.CarriageReturnLineFeed, trivia);
            var result = documentComment != null
                ? root.ReplaceNode(documentComment, comment.AdjustDocumentationCommentNewLineTrivia())
                : root.ReplaceNode(methodDeclaration, methodTrivia);

            var newDocument = context.Document.WithSyntaxRoot(result);
            return Task.FromResult(newDocument);
        }
コード例 #16
0
 /// <summary>
 /// Analyzes the top-level <c>&lt;summary&gt;</c> element of a documentation comment.
 /// </summary>
 /// <param name="context">The current analysis context.</param>
 /// <param name="documentation">The documentation syntax associated with the element.</param>
 /// <param name="syntax">The <see cref="XmlElementSyntax"/> or <see cref="XmlEmptyElementSyntax"/> of the node
 /// to examine.</param>
 /// <param name="completeDocumentation">The complete documentation for the declared symbol, with any
 /// <c>&lt;include&gt;</c> elements expanded. If the XML documentation comment included a <c>&lt;summary&gt;</c>
 /// element, this value will be <see langword="null"/>, even if the XML documentation comment also included an
 /// <c>&lt;include&gt;</c> element.</param>
 /// <param name="diagnosticLocations">The location(s) where diagnostics, if any, should be reported.</param>
 protected abstract void HandleXmlElement(SyntaxNodeAnalysisContext context, DocumentationCommentTriviaSyntax documentation, XmlNodeSyntax syntax, XElement completeDocumentation, params Location[] diagnosticLocations);
コード例 #17
0
		private IEnumerable<CompletionData> GetTagsForProperty(CompletionEngine engine, IPropertySymbol symbol, TextSpan filterSpan, DocumentationCommentTriviaSyntax trivia)
		{
			var items = new List<CompletionData>();

			var typeParameters = symbol.GetTypeArguments().Select(p => p.Name).ToSet();

			RemoveExistingTags(trivia, typeParameters, x => AttributeSelector(x, "typeparam"));

			items.AddRange(typeParameters.Select(t => engine.Factory.CreateXmlDocCompletionData(this, "typeparam", null, "name$" + t)));
			items.Add(engine.Factory.CreateXmlDocCompletionData(this, "value"));
			return items;
		}
コード例 #18
0
		private IEnumerable<CompletionData> GetTagsForType(CompletionEngine engine, INamedTypeSymbol symbol, TextSpan filterSpan, DocumentationCommentTriviaSyntax trivia)
		{
			var items = new List<CompletionData>();

			var typeParameters = symbol.TypeParameters.Select(p => p.Name).ToSet();

			RemoveExistingTags(trivia, typeParameters, x => AttributeSelector(x, "typeparam"));

			items.AddRange(typeParameters.Select(t => engine.Factory.CreateXmlDocCompletionData (
				this,
				FormatParameter("typeparam", t))));
			return items;
		}
コード例 #19
0
        private IEnumerable<CompletionItem> GetTagsForType(INamedTypeSymbol symbol, TextSpan itemSpan, DocumentationCommentTriviaSyntax trivia)
        {
            var items = new List<CompletionItem>();

            var typeParameters = symbol.TypeParameters.Select(p => p.Name).ToSet();

            RemoveExistingTags(trivia, typeParameters, x => AttributeSelector(x, TypeParamTagName));

            items.AddRange(typeParameters.Select(t => CreateCompletionItem(itemSpan, FormatParameter(TypeParamTagName, t))));
            return items;
        }
コード例 #20
0
            private IEnumerable<SyntaxTrivia> ConvertDocCommentToRegularComment(DocumentationCommentTriviaSyntax structuredTrivia)
            {
                var xmlFragment = DocumentationCommentUtilities.ExtractXMLFragment(structuredTrivia.ToFullString());

                var docComment = DocumentationComment.FromXmlFragment(xmlFragment);

                var commentLines = AbstractMetadataAsSourceService.DocCommentFormatter.Format(_formattingService, docComment);

                foreach (var line in commentLines)
                {
                    if (!string.IsNullOrWhiteSpace(line))
                    {
                        yield return SyntaxFactory.Comment("// " + line);
                    }
                    else
                    {
                        yield return SyntaxFactory.Comment("//");
                    }

                    yield return SyntaxFactory.ElasticCarriageReturnLineFeed;
                }
            }
コード例 #21
0
        private IEnumerable<CompletionItem> GetTagsForMethod(IMethodSymbol symbol, TextSpan itemSpan, DocumentationCommentTriviaSyntax trivia, SyntaxToken token)
        {
            var items = new List<CompletionItem>();

            var parameters = symbol.GetParameters().Select(p => p.Name).ToSet();
            var typeParameters = symbol.TypeParameters.Select(t => t.Name).ToSet();

            // User is trying to write a name, try to suggest only names.
            if (token.Parent.IsKind(SyntaxKind.XmlNameAttribute) ||
                (token.Parent.IsKind(SyntaxKind.IdentifierName) && token.Parent.IsParentKind(SyntaxKind.XmlNameAttribute)))
            {
                string parentElementName = null;

                var emptyElement = token.GetAncestor<XmlEmptyElementSyntax>();
                if (emptyElement != null)
                {
                    parentElementName = emptyElement.Name.LocalName.Text;
                }

                // We're writing the name of a paramref or typeparamref
                if (parentElementName == ParamRefTagName)
                {
                    items.AddRange(parameters.Select(p => CreateCompletionItem(itemSpan, p)));
                }
                else if (parentElementName == TypeParamRefTagName)
                {
                    items.AddRange(typeParameters.Select(t => CreateCompletionItem(itemSpan, t)));
                }

                return items;
            }

            RemoveExistingTags(trivia, parameters, x => AttributeSelector(x, ParamTagName));
            RemoveExistingTags(trivia, typeParameters, x => AttributeSelector(x, TypeParamTagName));

            items.AddRange(parameters.Select(p => CreateCompletionItem(itemSpan, FormatParameter(ParamTagName, p))));
            items.AddRange(typeParameters.Select(t => CreateCompletionItem(itemSpan, FormatParameter(TypeParamTagName, t))));

            // Provide a return completion item in case the function returns something
            var returns = true;

            foreach (var node in trivia.Content)
            {
                var element = node as XmlElementSyntax;
                if (element != null && !element.StartTag.IsMissing && !element.EndTag.IsMissing)
                {
                    var startTag = element.StartTag;

                    if (startTag.Name.LocalName.ValueText == ReturnsTagName)
                    {
                        returns = false;
                        break;
                    }
                }
            }

            if (returns && !symbol.ReturnsVoid)
            {
                items.Add(CreateCompletionItem(itemSpan, ReturnsTagName));
            }

            return items;
        }
コード例 #22
0
        private IEnumerable<CompletionItem> GetTagsForType(INamedTypeSymbol symbol, TextSpan filterSpan, DocumentationCommentTriviaSyntax trivia)
        {
            var items = new List<CompletionItem>();

            var typeParameters = symbol.TypeParameters.Select(p => p.Name).ToSet();

            RemoveExistingTags(trivia, typeParameters, x => AttributeSelector(x, "typeparam"));

            items.AddRange(typeParameters.Select(t => new XmlDocCommentCompletionItem(this,
                filterSpan,
                FormatParameter("typeparam", t), GetCompletionItemRules())));
            return items;
        }
コード例 #23
0
        internal static TNode RemoveSingleLineDocumentationComment <TNode>(TNode node, DocumentationCommentTriviaSyntax documentationComment) where TNode : SyntaxNode
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            if (!documentationComment.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia))
            {
                throw new ArgumentException($"Documentation comment's kind must be '{nameof(SyntaxKind.SingleLineDocumentationCommentTrivia)}'.", nameof(documentationComment));
            }

            SyntaxTrivia trivia = documentationComment.ParentTrivia;

            SyntaxToken token = trivia.Token;

            SyntaxTriviaList leadingTrivia = token.LeadingTrivia;

            int index = leadingTrivia.IndexOf(trivia);

            if (index >= 0 &&
                index < leadingTrivia.Count - 1 &&
                leadingTrivia[index + 1].IsWhitespaceTrivia())
            {
                SyntaxTriviaList newLeadingTrivia = leadingTrivia.RemoveRange(index, 2);

                SyntaxToken newToken = token.WithLeadingTrivia(newLeadingTrivia);

                return(node.ReplaceToken(token, newToken));
            }

            return(node.RemoveNode(documentationComment, SyntaxRemoveOptions.KeepNoTrivia));
        }
コード例 #24
0
        private IEnumerable<CompletionItem> GetTagsForMethod(IMethodSymbol symbol, TextSpan filterSpan, DocumentationCommentTriviaSyntax trivia, SyntaxToken token)
        {
            var items = new List<CompletionItem>();

            var parameters = symbol.GetParameters().Select(p => p.Name).ToSet();
            var typeParameters = symbol.TypeParameters.Select(t => t.Name).ToSet();

            // User is trying to write a name, try to suggest only names.
            if (token.Parent.IsKind(SyntaxKind.XmlNameAttribute) ||
                (token.Parent.IsKind(SyntaxKind.IdentifierName) && token.Parent.IsParentKind(SyntaxKind.XmlNameAttribute)))
            {
                string parentElementName = null;

                var emptyElement = token.GetAncestor<XmlEmptyElementSyntax>();
                if (emptyElement != null)
                {
                    parentElementName = emptyElement.Name.LocalName.Text;
                }

                // We're writing the name of a paramref or typeparamref
                if (parentElementName == "paramref")
                {
                    items.AddRange(parameters.Select(p => new XmlDocCommentCompletionItem(this, filterSpan, p, GetCompletionItemRules())));
                }
                else if (parentElementName == "typeparamref")
                {
                    items.AddRange(typeParameters.Select(t => new XmlDocCommentCompletionItem(this, filterSpan, t, GetCompletionItemRules())));
                }

                return items;
            }

            var returns = true;

            RemoveExistingTags(trivia, parameters, x => AttributeSelector(x, "param"));
            RemoveExistingTags(trivia, typeParameters, x => AttributeSelector(x, "typeparam"));

            foreach (var node in trivia.Content)
            {
                var element = node as XmlElementSyntax;
                if (element != null && !element.StartTag.IsMissing && !element.EndTag.IsMissing)
                {
                    var startTag = element.StartTag;

                    if (startTag.Name.LocalName.ValueText == "returns")
                    {
                        returns = false;
                        break;
                    }
                }
            }

            items.AddRange(parameters.Select(p => new XmlDocCommentCompletionItem(this, filterSpan, FormatParameter("param", p), GetCompletionItemRules())));
            items.AddRange(typeParameters.Select(t => new XmlDocCommentCompletionItem(this, filterSpan, FormatParameter("typeparam", t), GetCompletionItemRules())));

            if (returns && !symbol.ReturnsVoid)
            {
                items.Add(new XmlDocCommentCompletionItem(this, filterSpan, "returns", GetCompletionItemRules()));
            }

            return items;
        }
コード例 #25
0
//
//		public override bool SendEnterThroughToEditor(ICompletionData ICompletionData, string textTypedSoFar)
//		{
//			return false;
//		}

        private IEnumerable <CompletionData> GetTopLevelSingleUseNames(CompletionEngine engine, DocumentationCommentTriviaSyntax parentTrivia, TextSpan span)
        {
            var names = new HashSet <string>(new[] { "summary", "remarks", "example", "completionlist" });

            RemoveExistingTags(parentTrivia, names, (x) => x.StartTag.Name.LocalName.ValueText);

            return(names.Select(n => GetItem(engine, n, span)));
        }
コード例 #26
0
        private IEnumerable<CompletionItem> GetTagsForProperty(IPropertySymbol symbol, TextSpan filterSpan, DocumentationCommentTriviaSyntax trivia)
        {
            var items = new List<CompletionItem>();

            var typeParameters = symbol.GetTypeArguments().Select(p => p.Name).ToSet();

            RemoveExistingTags(trivia, typeParameters, x => AttributeSelector(x, "typeparam"));

            items.AddRange(typeParameters.Select(t => new XmlItem(this, filterSpan, "typeparam", "name", t)));
            items.Add(new XmlItem(this, filterSpan, "value"));
            return items;
        }
コード例 #27
0
        private IEnumerable <CompletionData> GetTagsForMethod(CompletionEngine engine, IMethodSymbol symbol, TextSpan filterSpan, DocumentationCommentTriviaSyntax trivia, SyntaxToken token)
        {
            var items = new List <CompletionData>();

            var parameters     = symbol.GetParameters().Select(p => p.Name).ToSet();
            var typeParameters = symbol.TypeParameters.Select(t => t.Name).ToSet();

            // User is trying to write a name, try to suggest only names.
            if (token.Parent.IsKind(SyntaxKind.XmlNameAttribute) ||
                (token.Parent.IsKind(SyntaxKind.IdentifierName) && token.Parent.IsParentKind(SyntaxKind.XmlNameAttribute)))
            {
                string parentElementName = null;

                var emptyElement = token.GetAncestor <XmlEmptyElementSyntax>();
                if (emptyElement != null)
                {
                    parentElementName = emptyElement.Name.LocalName.Text;
                }

                // We're writing the name of a paramref or typeparamref
                if (parentElementName == "paramref")
                {
                    items.AddRange(parameters.Select(p => engine.Factory.CreateXmlDocCompletionData(this, p)));
                }
                else if (parentElementName == "typeparamref")
                {
                    items.AddRange(typeParameters.Select(t => engine.Factory.CreateXmlDocCompletionData(this, t)));
                }

                return(items);
            }

            var returns = true;

            RemoveExistingTags(trivia, parameters, x => AttributeSelector(x, "param"));
            RemoveExistingTags(trivia, typeParameters, x => AttributeSelector(x, "typeparam"));

            foreach (var node in trivia.Content)
            {
                var element = node as XmlElementSyntax;
                if (element != null && !element.StartTag.IsMissing && !element.EndTag.IsMissing)
                {
                    var startTag = element.StartTag;

                    if (startTag.Name.LocalName.ValueText == "returns")
                    {
                        returns = false;
                        break;
                    }
                }
            }

            items.AddRange(parameters.Select(p => engine.Factory.CreateXmlDocCompletionData(this, FormatParameter("param", p))));
            items.AddRange(typeParameters.Select(t => engine.Factory.CreateXmlDocCompletionData(this, FormatParameter("typeparam", t))));

            if (returns && !symbol.ReturnsVoid)
            {
                items.Add(engine.Factory.CreateXmlDocCompletionData(this, "returns"));
            }

            return(items);
        }
コード例 #28
0
        private async Task <Document> CreateChangedDocument(CodeFixContext context, PropertyDeclarationSyntax propertyDeclarationSyntax, CancellationToken cancellationToken)
        {
            DocumentationCommentTriviaSyntax documentationComment = propertyDeclarationSyntax.GetDocumentationCommentTriviaSyntax();

            if (documentationComment == null)
            {
                return(context.Document);
            }

            XmlElementSyntax summaryElement = (XmlElementSyntax)documentationComment.Content.GetFirstXmlElement("summary");

            if (summaryElement == null)
            {
                return(context.Document);
            }

            SyntaxList <XmlNodeSyntax> summaryContent = summaryElement.Content;
            XmlNodeSyntax firstContent = summaryContent.FirstOrDefault(IsContentElement);
            XmlTextSyntax firstText    = firstContent as XmlTextSyntax;

            if (firstText != null)
            {
                string firstTextContent = string.Concat(firstText.DescendantTokens());
                if (firstTextContent.TrimStart().StartsWith("Gets ", StringComparison.Ordinal))
                {
                    // Find the token containing "Gets "
                    SyntaxToken getsToken = default(SyntaxToken);
                    foreach (SyntaxToken textToken in firstText.TextTokens)
                    {
                        if (textToken.IsMissing)
                        {
                            continue;
                        }

                        if (!textToken.Text.TrimStart().StartsWith("Gets ", StringComparison.Ordinal))
                        {
                            continue;
                        }

                        getsToken = textToken;
                        break;
                    }

                    if (!getsToken.IsMissing)
                    {
                        string text      = getsToken.Text;
                        string valueText = getsToken.ValueText;
                        int    index     = text.IndexOf("Gets ");
                        if (index >= 0)
                        {
                            bool additionalCharacters = index + 5 < text.Length;
                            text = text.Substring(0, index)
                                   + (additionalCharacters ? char.ToUpperInvariant(text[index + 5]).ToString() : string.Empty)
                                   + text.Substring(index + (additionalCharacters ? (5 + 1) : 5));
                        }

                        index = valueText.IndexOf("Gets ");
                        if (index >= 0)
                        {
                            valueText = valueText.Remove(index, 5);
                        }

                        SyntaxToken replaced = SyntaxFactory.Token(getsToken.LeadingTrivia, getsToken.Kind(), text, valueText, getsToken.TrailingTrivia);
                        summaryContent = summaryContent.Replace(firstText, firstText.ReplaceToken(getsToken, replaced));
                    }
                }
            }

            string        defaultValueToken = "NullIfNotIncluded";
            SemanticModel semanticModel     = await context.Document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclarationSyntax);

            if (propertySymbol != null)
            {
                ITypeSymbol propertyType = propertySymbol.Type;
                if (propertyType.IsImmutableArray())
                {
                    defaultValueToken = "DefaultArrayIfNotIncluded";
                }
            }

            XmlElementSyntax valueElement =
                XmlSyntaxFactory.MultiLineElement(
                    "value",
                    XmlSyntaxFactory.List(
                        XmlSyntaxFactory.ParaElement(XmlSyntaxFactory.PlaceholderElement(summaryContent.WithoutFirstAndLastNewlines())),
                        XmlSyntaxFactory.NewLine(),
                        XmlSyntaxFactory.TokenElement(defaultValueToken)));

            XmlNodeSyntax leadingNewLine = XmlSyntaxFactory.NewLine();

            // HACK: The formatter isn't working when contents are added to an existing documentation comment, so we
            // manually apply the indentation from the last line of the existing comment to each new line of the
            // generated content.
            SyntaxTrivia exteriorTrivia = GetLastDocumentationCommentExteriorTrivia(documentationComment);

            if (!exteriorTrivia.Token.IsMissing)
            {
                leadingNewLine = leadingNewLine.ReplaceExteriorTrivia(exteriorTrivia);
                valueElement   = valueElement.ReplaceExteriorTrivia(exteriorTrivia);
            }

            DocumentationCommentTriviaSyntax newDocumentationComment = documentationComment.WithContent(
                documentationComment.Content.InsertRange(documentationComment.Content.Count - 1,
                                                         XmlSyntaxFactory.List(
                                                             leadingNewLine,
                                                             valueElement)));

            SyntaxNode root = await context.Document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            SyntaxNode newRoot = root.ReplaceNode(documentationComment, newDocumentationComment);

            return(context.Document.WithSyntaxRoot(newRoot));
        }
        /// <summary>
        /// Add documentation for the property.
        /// </summary>
        /// <param name="context">the code fix context.</param>
        /// <param name="root">the root syntax node.</param>
        /// <param name="fieldDeclaration">the property declaration containing invalid documentation.</param>
        /// <param name="documentComment">the existing comment.</param>
        /// <returns>the correct code.</returns>
        private Task<Document> AddDocumentationAsync(
            CodeFixContext context,
            SyntaxNode root,
            FieldDeclarationSyntax fieldDeclaration,
            DocumentationCommentTriviaSyntax documentComment)
        {
            var @class = fieldDeclaration.Parent as ClassDeclarationSyntax;
            var first = @class?.DescendantNodes().FirstOrDefault() == fieldDeclaration;

            var summary = this._commentNodeFactory.CreateCommentSummaryText(fieldDeclaration);

            var comment = this._commentNodeFactory
                .CreateDocumentComment(summary)
                .WithAdditionalAnnotations(Formatter.Annotation);

            var trivia = SyntaxFactory.Trivia(comment);
            var pd = first
                ? fieldDeclaration.WithLeadingTrivia(trivia)
                : fieldDeclaration.WithLeadingTrivia(SyntaxFactory.CarriageReturnLineFeed, trivia);
            var result = documentComment != null
                ? root.ReplaceNode(documentComment, comment.AdjustDocumentationCommentNewLineTrivia())
                : root.ReplaceNode(fieldDeclaration, pd);

            var newDocument = context.Document.WithSyntaxRoot(result);
            return Task.FromResult(newDocument);
        }
コード例 #30
0
        private static void HandleMemberDeclaration(SyntaxNodeAnalysisContext context)
        {
            MemberDeclarationSyntax memberSyntax = (MemberDeclarationSyntax)context.Node;

            var modifiers = memberSyntax.GetModifiers();

            if (modifiers.Any(SyntaxKind.OverrideKeyword))
            {
                return;
            }

            DocumentationCommentTriviaSyntax documentation = memberSyntax.GetDocumentationCommentTriviaSyntax();
            if (documentation == null)
            {
                return;
            }

            Location location;

            ISymbol declaredSymbol = context.SemanticModel.GetDeclaredSymbol(memberSyntax, context.CancellationToken);
            if (declaredSymbol == null && memberSyntax.IsKind(SyntaxKind.EventFieldDeclaration))
            {
                var eventFieldDeclarationSyntax = (EventFieldDeclarationSyntax)memberSyntax;
                VariableDeclaratorSyntax firstVariable = eventFieldDeclarationSyntax.Declaration?.Variables.FirstOrDefault();
                if (firstVariable != null)
                {
                    declaredSymbol = context.SemanticModel.GetDeclaredSymbol(firstVariable, context.CancellationToken);
                }
            }

            if (documentation.Content.GetFirstXmlElement(XmlCommentHelper.IncludeXmlTag) is XmlEmptyElementSyntax includeElement)
            {
                if (declaredSymbol == null)
                {
                    return;
                }

                var rawDocumentation = declaredSymbol.GetDocumentationCommentXml(expandIncludes: true, cancellationToken: context.CancellationToken);
                var completeDocumentation = XElement.Parse(rawDocumentation, LoadOptions.None);

                var inheritDocElement = completeDocumentation.Nodes().OfType<XElement>().FirstOrDefault(element => element.Name == XmlCommentHelper.InheritdocXmlTag);
                if (inheritDocElement == null)
                {
                    return;
                }

                if (HasXmlCrefAttribute(inheritDocElement))
                {
                    return;
                }

                location = includeElement.GetLocation();
            }
            else
            {
                XmlNodeSyntax inheritDocElement = documentation.Content.GetFirstXmlElement(XmlCommentHelper.InheritdocXmlTag);
                if (inheritDocElement == null)
                {
                    return;
                }

                if (HasXmlCrefAttribute(inheritDocElement))
                {
                    return;
                }

                location = inheritDocElement.GetLocation();
            }

            // If we don't have a declared symbol we have some kind of field declaration. A field can not override or
            // implement anything so we want to report a diagnostic.
            if (declaredSymbol == null || !NamedTypeHelpers.IsImplementingAnInterfaceMember(declaredSymbol))
            {
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));
            }
        }
        /// <summary>
        /// add documentation for the constructor.
        /// </summary>
        /// <param name="context">the code fix context.</param>
        /// <param name="root">the syntax root.</param>
        /// <param name="constructorDeclaration">the constructor declaration syntax.</param>
        /// <param name="documentComment">the document content.</param>
        /// <returns>the resulting document.</returns>
        private Task<Document> AddDocumentationAsync(CodeFixContext context, SyntaxNode root, ConstructorDeclarationSyntax constructorDeclaration, DocumentationCommentTriviaSyntax documentComment)
        {
            var lines = documentComment.GetExistingSummaryCommentDocumentation() ?? new string[] { };
            var standardCommentText = this._commentNodeFactory.PrependStandardCommentText(constructorDeclaration, lines);

            var parameters = this._commentNodeFactory.CreateParameters(constructorDeclaration, documentComment);

            var summaryPlusParameters = new XmlNodeSyntax[] { standardCommentText }
                .Concat(parameters)
                .ToArray();

            var comment = this._commentNodeFactory
                .CreateDocumentComment(summaryPlusParameters)
                .AddLeadingEndOfLineTriviaFrom(constructorDeclaration.GetLeadingTrivia());

            var trivia = SyntaxFactory.Trivia(comment);
            var result = documentComment != null
                ? root.ReplaceNode(documentComment, comment.AdjustDocumentationCommentNewLineTrivia())
                : root.ReplaceNode(constructorDeclaration, constructorDeclaration.WithLeadingTrivia(trivia));

            var newDocument = context.Document.WithSyntaxRoot(result);
            return Task.FromResult(newDocument);
        }
コード例 #32
0
//
//		public override bool SendEnterThroughToEditor(ICompletionData ICompletionData, string textTypedSoFar)
//		{
//			return false;
//		}

		private IEnumerable<CompletionData> GetTopLevelSingleUseNames(CompletionEngine engine, DocumentationCommentTriviaSyntax parentTrivia, TextSpan span)
		{
			var names = new HashSet<string>(new[] { "summary", "remarks", "example", "completionlist" });

			RemoveExistingTags(parentTrivia, names, (x) => x.StartTag.Name.LocalName.ValueText);

			return names.Select(n => GetItem(engine, n, span));
		}
        private static void HandleBaseTypeLikeDeclaration(SyntaxNodeAnalysisContext context)
        {
            BaseTypeDeclarationSyntax baseType = context.Node as BaseTypeDeclarationSyntax;

            // baseType can be null here if we are looking at a delegate declaration
            if (baseType != null && baseType.BaseList != null && baseType.BaseList.Types.Any())
            {
                return;
            }

            DocumentationCommentTriviaSyntax documentation = context.Node.GetDocumentationCommentTriviaSyntax();

            if (documentation == null)
            {
                return;
            }

            Location location;

            var includeElement = documentation.Content.GetFirstXmlElement(XmlCommentHelper.IncludeXmlTag) as XmlEmptyElementSyntax;

            if (includeElement != null)
            {
                var declaration = context.SemanticModel.GetDeclaredSymbol(baseType, context.CancellationToken);
                if (declaration == null)
                {
                    return;
                }

                var rawDocumentation      = declaration.GetDocumentationCommentXml(expandIncludes: true, cancellationToken: context.CancellationToken);
                var completeDocumentation = XElement.Parse(rawDocumentation, LoadOptions.None);

                var inheritDocElement = completeDocumentation.Nodes().OfType <XElement>().FirstOrDefault(element => element.Name == XmlCommentHelper.InheritdocXmlTag);
                if (inheritDocElement == null)
                {
                    return;
                }

                if (HasXmlCrefAttribute(inheritDocElement))
                {
                    return;
                }

                location = includeElement.GetLocation();
            }
            else
            {
                XmlNodeSyntax inheritDocElement = documentation.Content.GetFirstXmlElement(XmlCommentHelper.InheritdocXmlTag);
                if (inheritDocElement == null)
                {
                    return;
                }

                if (HasXmlCrefAttribute(inheritDocElement))
                {
                    return;
                }

                location = inheritDocElement.GetLocation();
            }

            context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));
        }
        /// <summary>
        /// Add documentation for the property.
        /// </summary>
        /// <param name="context">the code fix context.</param>
        /// <param name="root">the root syntax node.</param>
        /// <param name="typeDeclaration">the property declaration containing invalid documentation.</param>
        /// <param name="documentComment">the existing comment.</param>
        /// <returns>the correct code.</returns>
        private Task<Document> AddDocumentationAsync(
            CodeFixContext context,
            SyntaxNode root,
            TypeDeclarationSyntax typeDeclaration,
            DocumentationCommentTriviaSyntax documentComment)
        {
            var summary = this._commentNodeFactory.CreateCommentSummaryText(typeDeclaration);
            var typeParameters = this._commentNodeFactory
                .CreateTypeParameters(typeDeclaration, documentComment)
                .ToArray();
            var all = typeParameters != null && typeParameters.Any()
                ? new XmlNodeSyntax[] { summary }.Concat(typeParameters).ToArray()
                : new XmlNodeSyntax[] { summary };

            var comment = this._commentNodeFactory
                .CreateDocumentComment(all)
                .WithAdditionalAnnotations(Formatter.Annotation);

            var trivia = SyntaxFactory.Trivia(comment);
            var replacement = typeDeclaration.WithLeadingTrivia(trivia);
            var result = root.ReplaceNode(typeDeclaration, replacement);

            var newDocument = context.Document.WithSyntaxRoot(result);
            return Task.FromResult(newDocument);
        }
コード例 #35
0
 public override void VisitDocumentationCommentTrivia(DocumentationCommentTriviaSyntax node)
 {
     return;
     //base.VisitDocumentationCommentTrivia(node);
 }
コード例 #36
0
 public override void VisitDocumentationCommentTrivia(DocumentationCommentTriviaSyntax node)
 {
     storedXmlComment.Add(node);
 }
コード例 #37
0
        private IEnumerable<CompletionItem> GetTopLevelSingleUseNames(DocumentationCommentTriviaSyntax parentTrivia, TextSpan span)
        {
            var names = new HashSet<string>(new[] { SummaryTagName, RemarksTagName, ExampleTagName, CompletionListTagName });

            RemoveExistingTags(parentTrivia, names, (x) => x.StartTag.Name.LocalName.ValueText);

            return names.Select(n => GetItem(n, span));
        }
コード例 #38
0
        private static bool ContainsXmlParseDiagnostic(DocumentationCommentTriviaSyntax node)
        {
            if (!node.ContainsDiagnostics)
            {
                return false;
            }

            foreach (Diagnostic diag in node.GetDiagnostics())
            {
                if ((ErrorCode)diag.Code == ErrorCode.WRN_XMLParseError)
                {
                    return true;
                }
            }

            return false;
        }
コード例 #39
0
        private IEnumerable<CompletionItem> GetTagsForSymbol(ISymbol symbol, TextSpan itemSpan, DocumentationCommentTriviaSyntax trivia, SyntaxToken token)
        {
            if (symbol is IMethodSymbol)
            {
                return GetTagsForMethod((IMethodSymbol)symbol, itemSpan, trivia, token);
            }

            if (symbol is IPropertySymbol)
            {
                return GetTagsForProperty((IPropertySymbol)symbol, itemSpan, trivia, token);
            }

            if (symbol is INamedTypeSymbol)
            {
                return GetTagsForType((INamedTypeSymbol)symbol, itemSpan, trivia);
            }

            return SpecializedCollections.EmptyEnumerable<CompletionItem>();
        }
コード例 #40
0
        private IEnumerable <CompletionItem> GetTagsForMethod(
            IMethodSymbol symbol, DocumentationCommentTriviaSyntax trivia, SyntaxToken token)
        {
            var items = new List <CompletionItem>();

            var parameters     = symbol.GetParameters().Select(p => p.Name).ToSet();
            var typeParameters = symbol.TypeParameters.Select(t => t.Name).ToSet();

            // User is trying to write a name, try to suggest only names.
            if (token.Parent.IsKind(SyntaxKind.XmlNameAttribute) ||
                (token.Parent.IsKind(SyntaxKind.IdentifierName) && token.Parent.IsParentKind(SyntaxKind.XmlNameAttribute)))
            {
                string parentElementName = null;

                var emptyElement = token.GetAncestor <XmlEmptyElementSyntax>();
                if (emptyElement != null)
                {
                    parentElementName = emptyElement.Name.LocalName.Text;
                }

                // We're writing the name of a paramref or typeparamref
                if (parentElementName == ParamRefTagName)
                {
                    items.AddRange(parameters.Select(CreateCompletionItem));
                }
                else if (parentElementName == TypeParamRefTagName)
                {
                    items.AddRange(typeParameters.Select(CreateCompletionItem));
                }

                return(items);
            }

            RemoveExistingTags(trivia, parameters, x => AttributeSelector(x, ParamTagName));
            RemoveExistingTags(trivia, typeParameters, x => AttributeSelector(x, TypeParamTagName));

            items.AddRange(parameters.Select(p => CreateCompletionItem(FormatParameter(ParamTagName, p))));
            items.AddRange(typeParameters.Select(t => CreateCompletionItem(FormatParameter(TypeParamTagName, t))));

            // Provide a return completion item in case the function returns something
            var returns = true;

            foreach (var node in trivia.Content)
            {
                var element = node as XmlElementSyntax;
                if (element != null && !element.StartTag.IsMissing && !element.EndTag.IsMissing)
                {
                    var startTag = element.StartTag;

                    if (startTag.Name.LocalName.ValueText == ReturnsTagName)
                    {
                        returns = false;
                        break;
                    }
                }
            }

            if (returns && !symbol.ReturnsVoid)
            {
                items.Add(CreateCompletionItem(ReturnsTagName));
            }

            return(items);
        }
コード例 #41
0
        private IEnumerable<CompletionItem> GetTagsForProperty(IPropertySymbol symbol, TextSpan itemSpan, DocumentationCommentTriviaSyntax trivia, SyntaxToken token)
        {
            var items = new List<CompletionItem>();

            if (symbol.IsIndexer)
            {
                var parameters = symbol.GetParameters().Select(p => p.Name).ToSet();

                // User is trying to write a name, try to suggest only names.
                if (token.Parent.IsKind(SyntaxKind.XmlNameAttribute) ||
                    (token.Parent.IsKind(SyntaxKind.IdentifierName) && token.Parent.IsParentKind(SyntaxKind.XmlNameAttribute)))
                {
                    string parentElementName = null;

                    var emptyElement = token.GetAncestor<XmlEmptyElementSyntax>();
                    if (emptyElement != null)
                    {
                        parentElementName = emptyElement.Name.LocalName.Text;
                    }

                    // We're writing the name of a paramref
                    if (parentElementName == ParamRefTagName)
                    {
                        items.AddRange(parameters.Select(p => CreateCompletionItem(itemSpan, p)));
                    }

                    return items;
                }

                RemoveExistingTags(trivia, parameters, x => AttributeSelector(x, ParamTagName));
                items.AddRange(parameters.Select(p => CreateCompletionItem(itemSpan, FormatParameter(ParamTagName, p))));
            }

            var typeParameters = symbol.GetTypeArguments().Select(p => p.Name).ToSet();
            items.AddRange(typeParameters.Select(t => CreateCompletionItem(itemSpan, TypeParamTagName, NameAttributeName, t)));
            items.Add(CreateCompletionItem(itemSpan, "value"));
            return items;
        }
コード例 #42
0
                private MethodDeclarationSyntax AbstractRequestMethod(bool sync, bool callSettings, IEnumerable <ParameterInfo> parameters, DocumentationCommentTriviaSyntax returnsXmlDoc = null)
                {
                    var returnTyp        = sync ? MethodDetails.SyncReturnTyp : MethodDetails.AsyncReturnTyp;
                    var methodName       = sync ? MethodDetails.SyncMethodName : MethodDetails.AsyncMethodName;
                    var finalParam       = callSettings ? _def.CallSettingsParam : _def.CancellationTokenParam;
                    var finalParamXmlDoc = callSettings ? _def.CallSettingsXmlDoc : _def.CancellationTokenXmlDoc;

                    returnsXmlDoc = returnsXmlDoc ?? (sync ?
                                                      MethodDetails is MethodDetails.Paginated ? _def.ReturnsSyncPaginatedXmlDoc : _def.ReturnsSyncXmlDoc :
                                                      MethodDetails is MethodDetails.Paginated ? _def.ReturnsAsyncPaginatedXmlDoc : _def.ReturnsAsyncXmlDoc);
                    if (callSettings)
                    {
                        return(Method(Public | Virtual, Ctx.Type(returnTyp), methodName)(parameters.Select(x => x.Parameter).Append(finalParam).ToArray())
                               .WithBody(This.Call(methodName)(New(Ctx.Type(MethodDetails.RequestTyp))()
                                                               .WithInitializer(NestInit(parameters, 0).ToArray()), finalParam))
                               .WithXmlDoc(parameters.Select(x => x.XmlDoc).Prepend(_def.SummaryXmlDoc).Append(finalParamXmlDoc).Append(returnsXmlDoc).ToArray()));

                        IEnumerable <ObjectInitExpr> NestInit(IEnumerable <ParameterInfo> ps, int ofs)
                        {
                            var byField = ps.GroupBy(x => (x.FieldDescs ?? Enumerable.Empty <FieldDescriptor>()).Skip(ofs).SkipLast(1).FirstOrDefault())
                                          .OrderBy(x => x.Key?.Index);

                            foreach (var f in byField)
                            {
                                if (f.Key == null)
                                {
                                    // No more nesting, these are the actual fields that need filling.
                                    foreach (var param in f.OrderBy(x => x.FieldDescs?.Last().Index ?? int.MaxValue))
                                    {
                                        yield return((param.InitExpr as ObjectInitExpr) ??
                                                     new ObjectInitExpr(param.ResourcePropertyName ?? param.FieldDescs.Last().CSharpPropertyName(), param.InitExpr,
                                                                        isDeprecated: param.FieldDescs.Last().IsDeprecated()));
                                    }
                                }
                                else
                                {
                                    // Nested field.
                                    var code = New(Ctx.Type(ProtoTyp.Of(f.Key)))().WithInitializer(NestInit(f, ofs + 1).ToArray());
                                    yield return(new ObjectInitExpr(f.Key.CSharpPropertyName(), code));
                                }
                            }
                        }
                    }
                    else
                    {
                        return(Method(Public | Virtual, Ctx.Type(returnTyp), methodName)(parameters.Select(x => x.Parameter).Append(finalParam).ToArray())
                               .WithBody(This.Call(methodName)(parameters.Select(x => (object)x.Parameter).Append(
                                                                   Ctx.Type <CallSettings>().Call(nameof(CallSettings.FromCancellationToken))(finalParam))))
                               .WithXmlDoc(parameters.Select(x => x.XmlDoc).Prepend(_def.SummaryXmlDoc).Append(finalParamXmlDoc).Append(returnsXmlDoc).ToArray()));
                    }
                }
コード例 #43
0
 public ParsedType(BaseTypeDeclarationSyntax type, DocumentationCommentTriviaSyntax documentation) : base(documentation)
 {
     _declarationType = type;
 }
コード例 #44
0
 public ParameterInfo(IReadOnlyList <FieldDescriptor> fieldDescs, ParameterSyntax parameter, object initExpr,
                      string resourcePropertyName, DocumentationCommentTriviaSyntax xmlDoc) =>
 (FieldDescs, Parameter, InitExpr, ResourcePropertyName, XmlDoc) = (fieldDescs, parameter, initExpr, resourcePropertyName, xmlDoc);
コード例 #45
0
        private static async Task <Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
        {
            var documentRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            SyntaxNode syntax = documentRoot.FindNode(diagnostic.Location.SourceSpan);

            if (syntax == null)
            {
                return(document);
            }

            MethodDeclarationSyntax   methodDeclarationSyntax   = syntax.FirstAncestorOrSelf <MethodDeclarationSyntax>();
            DelegateDeclarationSyntax delegateDeclarationSyntax = syntax.FirstAncestorOrSelf <DelegateDeclarationSyntax>();

            if (methodDeclarationSyntax == null && delegateDeclarationSyntax == null)
            {
                return(document);
            }

            DocumentationCommentTriviaSyntax documentationComment =
                methodDeclarationSyntax?.GetDocumentationCommentTriviaSyntax()
                ?? delegateDeclarationSyntax?.GetDocumentationCommentTriviaSyntax();

            if (documentationComment == null)
            {
                return(document);
            }

            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            bool isTask;
            bool isAsynchronousTestMethod;

            if (methodDeclarationSyntax != null)
            {
                isTask = IsTaskReturningMethod(semanticModel, methodDeclarationSyntax, cancellationToken);
                isAsynchronousTestMethod = isTask && IsAsynchronousTestMethod(semanticModel, methodDeclarationSyntax, cancellationToken);
            }
            else
            {
                isTask = IsTaskReturningMethod(semanticModel, delegateDeclarationSyntax, cancellationToken);
                isAsynchronousTestMethod = false;
            }

            XmlNodeSyntax returnsElement = documentationComment.Content.GetFirstXmlElement(XmlCommentHelper.ReturnsXmlTag) as XmlNodeSyntax;

            if (returnsElement != null && !isTask)
            {
                // This code fix doesn't know how to do anything more than document Task-returning methods.
                return(document);
            }

            SyntaxList <XmlNodeSyntax> content = XmlSyntaxFactory.List();

            if (isTask)
            {
                content = content.Add(XmlSyntaxFactory.Text("A "));
                content = content.Add(XmlSyntaxFactory.SeeElement(SyntaxFactory.TypeCref(SyntaxFactory.ParseTypeName("global::System.Threading.Tasks.Task"))).WithAdditionalAnnotations(Simplifier.Annotation));
                string operationKind = isAsynchronousTestMethod ? "unit test" : "operation";
                content = content.Add(XmlSyntaxFactory.Text($" representing the asynchronous {operationKind}."));

                // wrap the generated content in a <placeholder> element for review.
                content = XmlSyntaxFactory.List(XmlSyntaxFactory.PlaceholderElement(content));
            }

            // Try to replace an existing <returns> element if the comment contains one. Otherwise, add it as a new element.
            SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            SyntaxNode newRoot;

            if (returnsElement != null)
            {
                XmlEmptyElementSyntax emptyElement = returnsElement as XmlEmptyElementSyntax;
                if (emptyElement != null)
                {
                    XmlElementSyntax updatedReturns = XmlSyntaxFactory.Element(XmlCommentHelper.ReturnsXmlTag, content)
                                                      .WithLeadingTrivia(returnsElement.GetLeadingTrivia())
                                                      .WithTrailingTrivia(returnsElement.GetTrailingTrivia());
                    newRoot = root.ReplaceNode(returnsElement, updatedReturns);
                }
                else
                {
                    XmlElementSyntax updatedReturns = ((XmlElementSyntax)returnsElement).WithContent(content);
                    newRoot = root.ReplaceNode(returnsElement, updatedReturns);
                }
            }
            else
            {
                string newLineText = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp);

                returnsElement = XmlSyntaxFactory.Element(XmlCommentHelper.ReturnsXmlTag, content);

                XmlNodeSyntax leadingNewLine = XmlSyntaxFactory.NewLine(newLineText);

                // HACK: The formatter isn't working when contents are added to an existing documentation comment, so we
                // manually apply the indentation from the last line of the existing comment to each new line of the
                // generated content.
                SyntaxTrivia exteriorTrivia = GetLastDocumentationCommentExteriorTrivia(documentationComment);
                if (!exteriorTrivia.Token.IsMissing)
                {
                    leadingNewLine = leadingNewLine.ReplaceExteriorTrivia(exteriorTrivia);
                    returnsElement = returnsElement.ReplaceExteriorTrivia(exteriorTrivia);
                }

                DocumentationCommentTriviaSyntax newDocumentationComment = documentationComment.WithContent(
                    documentationComment.Content.InsertRange(
                        documentationComment.Content.Count - 1,
                        XmlSyntaxFactory.List(leadingNewLine, returnsElement)));

                newRoot = root.ReplaceNode(documentationComment, newDocumentationComment);
            }

            return(document.WithSyntaxRoot(newRoot));
        }
コード例 #46
0
 public static XmlElementSyntax GetXmlCommentParam(this DocumentationCommentTriviaSyntax documentationSyntax, string xmlParamName) =>
 documentationSyntax?.ChildNodes()
 .OfType <XmlElementSyntax>()
 .FirstOrDefault(xmlElementSyntax => xmlElementSyntax.IsXmlCommentParam(xmlParamName));
        /// <inheritdoc/>
        protected override void HandleXmlElement(SyntaxNodeAnalysisContext context, bool needsComment, DocumentationCommentTriviaSyntax documentation, XmlNodeSyntax syntax, XElement completeDocumentation, Location[] diagnosticLocations)
        {
            if (!needsComment)
            {
                // A missing summary is allowed for this element.
                return;
            }

            if (completeDocumentation != null)
            {
                // We are working with an <include> element
                if (completeDocumentation.Nodes().OfType <XElement>().Any(element => element.Name == XmlCommentHelper.SummaryXmlTag))
                {
                    return;
                }

                if (completeDocumentation.Nodes().OfType <XElement>().Any(element => element.Name == XmlCommentHelper.InheritdocXmlTag))
                {
                    // Ignore nodes with an <inheritdoc/> tag in the included XML.
                    return;
                }
            }
            else
            {
                if (syntax != null)
                {
                    return;
                }

                if (documentation?.Content.GetFirstXmlElement(XmlCommentHelper.InheritdocXmlTag) != null)
                {
                    // Ignore nodes with an <inheritdoc/> tag.
                    return;
                }
            }

            foreach (var location in diagnosticLocations)
            {
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));
            }
        }
コード例 #48
0
        public static ImmutableArray <string> GetAttributeValues(DocumentationCommentTriviaSyntax comment, string elementName, string attributeName)
        {
            HashSet <string> values = null;

            bool containsInclude = false;
            bool isFirst         = true;

            foreach (XmlNodeSyntax node in comment.Content)
            {
                SyntaxKind kind = node.Kind();

                if (kind == SyntaxKind.XmlElement)
                {
                    var element = (XmlElementSyntax)node;

                    string name = element.StartTag?.Name?.LocalName.ValueText;

                    if (name != null)
                    {
                        if (isFirst)
                        {
                            if (NameEquals(name, "include"))
                            {
                                containsInclude = true;
                            }

                            isFirst = false;
                        }
                        else
                        {
                            containsInclude = false;
                        }

                        if (NameEquals(name, "inheritdoc"))
                        {
                            return(default(ImmutableArray <string>));
                        }
                        else if (NameEquals(name, elementName))
                        {
                            string value = GetAttributeValue(element, attributeName);

                            if (value != null)
                            {
                                (values ?? (values = new HashSet <string>())).Add(value);
                            }
                        }
                    }
                }

                if (kind == SyntaxKind.XmlEmptyElement)
                {
                    var element = (XmlEmptyElementSyntax)node;

                    string name = element?.Name?.LocalName.ValueText;

                    if (name != null)
                    {
                        if (isFirst)
                        {
                            if (NameEquals(name, "include"))
                            {
                                containsInclude = true;
                            }

                            isFirst = false;
                        }
                        else
                        {
                            containsInclude = false;
                        }

                        if (NameEquals(name, "inheritdoc"))
                        {
                            return(default(ImmutableArray <string>));
                        }
                    }
                }
            }

            if (!containsInclude)
            {
                return(values?.ToImmutableArray() ?? ImmutableArray <string> .Empty);
            }

            return(default(ImmutableArray <string>));
        }
コード例 #49
0
 public override void VisitDocumentationCommentTrivia(DocumentationCommentTriviaSyntax node)
 {
     storedXmlComment.Add(node);
 }
コード例 #50
0
 private XmlEmptyElementSyntax GetXmlExcludeTag(DocumentationCommentTriviaSyntax xmlComment) =>
 xmlComment
 .ChildNodes()
 .OfType <XmlEmptyElementSyntax>()
 .FirstOrDefault(s => XmlCommentExcludeTag.Equals(s.Name?.ToString(), StringComparison.Ordinal));
コード例 #51
0
        private IEnumerable <CompletionData> GetTagsForSymbol(CompletionEngine engine, ISymbol symbol, TextSpan filterSpan, DocumentationCommentTriviaSyntax trivia, SyntaxToken token)
        {
            if (symbol is IMethodSymbol)
            {
                return(GetTagsForMethod(engine, (IMethodSymbol)symbol, filterSpan, trivia, token));
            }

            if (symbol is IPropertySymbol)
            {
                return(GetTagsForProperty(engine, (IPropertySymbol)symbol, filterSpan, trivia));
            }

            if (symbol is INamedTypeSymbol)
            {
                return(GetTagsForType(engine, (INamedTypeSymbol)symbol, filterSpan, trivia));
            }

            return(SpecializedCollections.EmptyEnumerable <CompletionData>());
        }
コード例 #52
0
 private XmlElementSyntax GetSummaryTag(DocumentationCommentTriviaSyntax xmlComment) =>
 xmlComment
 .ChildNodes()
 .OfType <XmlElementSyntax>()
 .FirstOrDefault(n => XmlCommentSummaryTag.Equals(n.StartTag?.Name?.ToString(), StringComparison.Ordinal));
コード例 #53
0
        private IEnumerable <CompletionData> GetTagsForProperty(CompletionEngine engine, IPropertySymbol symbol, TextSpan filterSpan, DocumentationCommentTriviaSyntax trivia)
        {
            var items = new List <CompletionData>();

            var typeParameters = symbol.GetTypeArguments().Select(p => p.Name).ToSet();

            RemoveExistingTags(trivia, typeParameters, x => AttributeSelector(x, "typeparam"));

            items.AddRange(typeParameters.Select(t => engine.Factory.CreateXmlDocCompletionData(this, "typeparam", null, "name$" + t)));
            items.Add(engine.Factory.CreateXmlDocCompletionData(this, "value"));
            return(items);
        }
コード例 #54
0
ファイル: Triva.cs プロジェクト: binarybird/Cascade
 public override Evaluation VisitDocumentationCommentTrivia(DocumentationCommentTriviaSyntax node)
 {
     return(base.VisitDocumentationCommentTrivia(node));
 }
コード例 #55
0
        private static bool CanAddExceptionToComment(
            DocumentationCommentTriviaSyntax comment,
            INamedTypeSymbol exceptionSymbol,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            var containsException        = false;
            var containsIncludeOrExclude = false;
            var isFirst = true;

            foreach (XmlNodeSyntax node in comment.Content)
            {
                XmlElementInfo info = SyntaxInfo.XmlElementInfo(node);
                if (info.Success)
                {
                    switch (info.GetTag())
                    {
                    case XmlTag.Include:
                    case XmlTag.Exclude:
                    {
                        if (isFirst)
                        {
                            containsIncludeOrExclude = true;
                        }

                        break;
                    }

                    case XmlTag.InheritDoc:
                    {
                        return(false);
                    }

                    case XmlTag.Exception:
                    {
                        if (!containsException)
                        {
                            if (info.IsEmptyElement)
                            {
                                containsException = ContainsException((XmlEmptyElementSyntax)info.Element, exceptionSymbol, semanticModel, cancellationToken);
                            }
                            else
                            {
                                containsException = ContainsException((XmlElementSyntax)info.Element, exceptionSymbol, semanticModel, cancellationToken);
                            }
                        }

                        break;
                    }
                    }

                    if (isFirst)
                    {
                        isFirst = false;
                    }
                    else
                    {
                        containsIncludeOrExclude = false;
                    }
                }
            }

            return(!containsIncludeOrExclude &&
                   !containsException);
        }
コード例 #56
0
        private void HandleNamedType(SymbolAnalysisContext context)
        {
            INamedTypeSymbol symbol = (INamedTypeSymbol)context.Symbol;

            if (symbol.TypeKind != TypeKind.Class)
            {
                return;
            }

            if (!symbol.IsExtensibleJsonObject())
            {
                return;
            }

            foreach (var propertySymbol in symbol.GetMembers().OfType <IPropertySymbol>())
            {
                if (propertySymbol.SetMethod != null)
                {
                    continue;
                }

                var locations = propertySymbol.Locations;
                if (locations.IsDefaultOrEmpty)
                {
                    continue;
                }

                var tree = locations[0].SourceTree;
                if (tree == null)
                {
                    continue;
                }

                var root           = tree.GetRoot(context.CancellationToken);
                var node           = root.FindNode(locations[0].SourceSpan, getInnermostNodeForTie: true);
                var propertySyntax = node.FirstAncestorOrSelf <PropertyDeclarationSyntax>();
                var getter         = propertySyntax.AccessorList?.Accessors.FirstOrDefault(i => i.Keyword.IsKind(SyntaxKind.GetKeyword));
                if (!(getter?.Body?.Statements.Count == 1))
                {
                    continue;
                }

                ReturnStatementSyntax returnStatement  = getter?.Body?.Statements.FirstOrDefault() as ReturnStatementSyntax;
                ExpressionSyntax      returnExpression = returnStatement.Expression;
                if (returnExpression.IsKind(SyntaxKind.SimpleMemberAccessExpression))
                {
                    MemberAccessExpressionSyntax memberAccess = (MemberAccessExpressionSyntax)returnExpression;
                    if (!memberAccess.Expression.IsKind(SyntaxKind.ThisExpression))
                    {
                        continue;
                    }
                }

                SemanticModel semanticModel = context.Compilation.GetSemanticModel(tree);
                SymbolInfo    symbolInfo    = semanticModel.GetSymbolInfo(returnExpression, context.CancellationToken);
                IFieldSymbol  fieldSymbol   = symbolInfo.Symbol as IFieldSymbol;
                if (fieldSymbol.ContainingType != propertySymbol.ContainingType)
                {
                    continue;
                }

                if (!fieldSymbol.GetAttributes().Any(i => string.Equals("global::Newtonsoft.Json.JsonPropertyAttribute", i.AttributeClass.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), StringComparison.Ordinal)))
                {
                    continue;
                }

                DocumentationCommentTriviaSyntax documentationCommentSyntax = propertySyntax.GetDocumentationCommentTriviaSyntax();
                if (documentationCommentSyntax == null)
                {
                    continue;
                }

                XmlNodeSyntax valueNode = documentationCommentSyntax.Content.GetFirstXmlElement("value");
                if (valueNode == null)
                {
                    continue;
                }

                string      defaultValueToken = "NullIfNotIncluded";
                ITypeSymbol propertyType      = propertySymbol.Type;
                if (propertyType.IsImmutableArray())
                {
                    defaultValueToken = "DefaultArrayIfNotIncluded";
                }

                XmlElementSyntax valueElementSyntax = valueNode as XmlElementSyntax;
                if (valueElementSyntax != null)
                {
                    bool foundToken = false;
                    foreach (XmlElementSyntax valueElementChild in valueElementSyntax.Content.OfType <XmlElementSyntax>())
                    {
                        if (!string.Equals("token", valueElementChild.StartTag?.Name?.ToString(), StringComparison.Ordinal))
                        {
                            continue;
                        }

                        if (!string.Equals(defaultValueToken, valueElementChild.Content.ToFullString()))
                        {
                            continue;
                        }

                        foundToken = true;
                        break;
                    }

                    if (foundToken)
                    {
                        continue;
                    }
                }

                string propertyTypeName = propertyType.ToMinimalDisplayString(semanticModel, returnExpression.SpanStart, SymbolDisplayFormat.CSharpErrorMessageFormat);
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, valueNode.GetLocation(), propertyTypeName, defaultValueToken));
            }
        }
コード例 #57
0
        static string DocCommentToPythonDoc(DocumentationCommentTriviaSyntax doccomment, int indentLevel)
        {
            StringBuilder summary = new StringBuilder();
            StringBuilder args    = new StringBuilder();
            StringBuilder returns = new StringBuilder();


            string comment = doccomment.ToString();

            comment = comment.Replace("///", "");
            comment = comment.Replace("\t", " ");
            var doc = new System.Xml.XmlDocument();

            doc.LoadXml("<doc>" + comment + "</doc>");
            var nodes = doc.FirstChild.ChildNodes;

            foreach (var node in nodes)
            {
                var    element     = node as System.Xml.XmlElement;
                string elementText = element.InnerText.Trim();
                if (string.IsNullOrWhiteSpace(elementText))
                {
                    continue;
                }
                string[] lines = elementText.Split(new char[] { '\n' });

                if (element.Name.Equals("summary", StringComparison.OrdinalIgnoreCase))
                {
                    foreach (var line in lines)
                    {
                        summary.AppendLine(_T(indentLevel) + line.Trim());
                    }
                }
                else if (element.Name.Equals("returns", StringComparison.OrdinalIgnoreCase))
                {
                    returns.AppendLine();
                    returns.AppendLine(_T(indentLevel) + "Returns:");
                    foreach (var line in lines)
                    {
                        returns.AppendLine(_T(indentLevel + 1) + line.Trim());
                    }
                }
                else if (element.Name.Equals("param", StringComparison.OrdinalIgnoreCase))
                {
                    if (args.Length == 0)
                    {
                        args.AppendLine();
                        args.AppendLine(_T(indentLevel) + "Args:");
                    }
                    string parameterName = element.GetAttribute("name");

                    bool added = false;
                    foreach (var line in lines)
                    {
                        if (!added)
                        {
                            args.AppendLine(_T(indentLevel + 1) + parameterName + " : " + line.Trim());
                            continue;
                        }
                        added = true;
                        args.AppendLine(_T(indentLevel + 1) + line.Trim());
                    }
                }
            }
            StringBuilder rc = new StringBuilder();

            rc.AppendLine(_T(indentLevel) + "\"\"\"");
            rc.Append(summary.ToString());
            rc.Append(args.ToString());
            rc.Append(returns.ToString());
            rc.AppendLine(_T(indentLevel) + "\"\"\"");
            return(rc.ToString());
        }
コード例 #58
0
        public static void Analyze(SyntaxNodeAnalysisContext context, DocumentationCommentTriviaSyntax documentationComment)
        {
            bool containsInheritDoc     = false;
            bool containsInclude        = false;
            bool containsSummaryElement = false;

            bool isFirst = true;

            foreach (XmlNodeSyntax node in documentationComment.Content)
            {
                SyntaxKind kind = node.Kind();

                if (kind == SyntaxKind.XmlElement)
                {
                    var element = (XmlElementSyntax)node;

                    string name = element.StartTag?.Name?.LocalName.ValueText;

                    if (name != null)
                    {
                        if (isFirst)
                        {
                            if (IsInclude(name))
                            {
                                containsInclude = true;
                            }

                            isFirst = false;
                        }
                        else
                        {
                            containsInclude = false;
                        }

                        if (IsInheritDoc(name))
                        {
                            containsInheritDoc = true;
                        }
                        else if (IsSummary(name))
                        {
                            if (IsSummaryMissing(element))
                            {
                                context.ReportDiagnostic(
                                    DiagnosticDescriptors.AddSummaryToDocumentationComment,
                                    element);
                            }

                            containsSummaryElement = true;
                        }

                        if (containsInheritDoc && containsSummaryElement)
                        {
                            break;
                        }
                    }
                }
                else if (kind == SyntaxKind.XmlEmptyElement)
                {
                    var element = (XmlEmptyElementSyntax)node;

                    string name = element.Name?.LocalName.ValueText;

                    if (name != null)
                    {
                        if (isFirst)
                        {
                            if (IsInclude(name))
                            {
                                containsInclude = true;
                            }

                            isFirst = false;
                        }
                        else
                        {
                            containsInclude = false;
                        }

                        if (IsInheritDoc(name))
                        {
                            containsInheritDoc = true;
                        }
                        else if (IsSummary(name))
                        {
                            context.ReportDiagnostic(
                                DiagnosticDescriptors.AddSummaryToDocumentationComment,
                                element);

                            containsSummaryElement = true;
                        }

                        if (containsInheritDoc && containsSummaryElement)
                        {
                            break;
                        }
                    }
                }
            }

            if (!containsSummaryElement &&
                !containsInheritDoc &&
                !containsInclude)
            {
                context.ReportDiagnostic(
                    DiagnosticDescriptors.AddSummaryElementToDocumentationComment,
                    documentationComment);
            }
        }
コード例 #59
0
        public static string DocCommentToPythonDoc(
            DocumentationCommentTriviaSyntax doccomment, MethodDeclarationSyntax method,
            int indentLevel, out StringBuilder summary, out List <ParameterInfo> parameters, out ReturnInfo returnInfo)
        {
            // See https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html
            // for docstring examples

            summary = new StringBuilder();
            StringBuilder args    = new StringBuilder();
            StringBuilder returns = new StringBuilder();
            StringBuilder outArgs = new StringBuilder();

            parameters = new List <ParameterInfo>();
            returnInfo = new ReturnInfo()
            {
                Type = method.ReturnType.ToString()
            };
            if (doccomment == null)
            {
                return("");
            }
            var doc   = DocCommentToXml(doccomment);
            var nodes = doc.FirstChild.ChildNodes;

            foreach (var node in nodes)
            {
                var    element     = node as System.Xml.XmlElement;
                string elementText = element.InnerText.Trim();
                if (string.IsNullOrWhiteSpace(elementText))
                {
                    continue;
                }
                string[] lines = elementText.Split(new char[] { '\n' });

                if (element.Name.Equals("summary", StringComparison.OrdinalIgnoreCase))
                {
                    foreach (var line in lines)
                    {
                        summary.AppendLine(_T(indentLevel) + line.Trim());
                    }
                }
                else if (element.Name.Equals("returns", StringComparison.OrdinalIgnoreCase))
                {
                    returns.AppendLine();
                    returns.AppendLine(_T(indentLevel) + "Returns:");
                    returns.Append(_T(indentLevel + 1) + $"{method.ReturnType}: ");
                    bool firstLine = true;
                    foreach (var line in lines)
                    {
                        returnInfo.Description.Add(line.Trim());
                        if (!firstLine)
                        {
                            returns.Append(_T(indentLevel + 1));
                        }
                        firstLine = false;
                        returns.AppendLine(line.Trim());
                    }
                }
                else if (element.Name.Equals("param", StringComparison.OrdinalIgnoreCase))
                {
                    string        parameterName = element.GetAttribute("name");
                    ParameterInfo pinfo         = new ParameterInfo {
                        Name = parameterName
                    };
                    string paramType  = "";
                    bool   isOutParam = false;
                    foreach (var param in method.ParameterList.Parameters)
                    {
                        if (param.Identifier.ToString().Equals(parameterName, StringComparison.Ordinal))
                        {
                            isOutParam = IsOutParameter(param);
                            paramType  = $" ({param.Type})";
                            pinfo.Type = param.Type.ToString();
                        }
                    }

                    if (args.Length == 0 && !isOutParam)
                    {
                        args.AppendLine();
                        args.AppendLine(_T(indentLevel) + "Args:");
                    }

                    bool          added = false;
                    StringBuilder sb    = isOutParam ? outArgs : args;
                    foreach (var line in lines)
                    {
                        pinfo.Description.Add(line.Trim());
                        if (!added)
                        {
                            added = true;
                            sb.AppendLine(_T(indentLevel + 1) + parameterName + paramType + ": " + line.Trim());
                            continue;
                        }
                        sb.AppendLine(_T(indentLevel + 2) + line.Trim());
                    }
                    if (!isOutParam)
                    {
                        parameters.Add(pinfo);
                    }
                }
            }

            StringBuilder rc = new StringBuilder();

            rc.AppendLine(_T(indentLevel) + "\"\"\"");
            rc.Append(summary.ToString());
            rc.Append(args.ToString());
            rc.Append(returns.ToString());
            rc.Append(outArgs.ToString());
            rc.AppendLine(_T(indentLevel) + "\"\"\"");
            return(rc.ToString());
        }
コード例 #60
0
        private IEnumerable<CompletionItem> GetTagsForProperty(IPropertySymbol symbol, DocumentationCommentTriviaSyntax trivia)
        {
            var items = new List<CompletionItem>();

            if (symbol.IsIndexer)
            {
                var parameters = symbol.GetParameters().Select(p => p.Name).ToSet();
                RemoveExistingTags(trivia, parameters, x => AttributeSelector(x, ParamTagName));
                items.AddRange(parameters.Select(p => CreateCompletionItem(FormatParameter(ParamTagName, p))));
            }

            var typeParameters = symbol.GetTypeArguments().Select(p => p.Name).ToSet();
            items.AddRange(typeParameters.Select(t => CreateCompletionItem(TypeParamTagName, NameAttributeName, t)));
            items.Add(CreateCompletionItem("value"));
            return items;
        }