예제 #1
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out XmlNodeSyntax xmlNode, findInsideTrivia: true))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.UnusedElementInDocumentationComment:
                {
                    XmlElementInfo elementInfo = SyntaxInfo.XmlElementInfo(xmlNode);

                    string name = elementInfo.LocalName;

                    CodeAction codeAction = CodeAction.Create(
                        $"Remove element '{name}'",
                        cancellationToken => RemoveUnusedElementInDocumentationCommentAsync(context.Document, elementInfo, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
예제 #2
0
        private static void Analyze <TNode>(
            SyntaxNodeAnalysisContext context,
            SyntaxList <XmlNodeSyntax> xmlNodes,
            SeparatedSyntaxList <TNode> nodes,
            XmlTag tag,
            Func <SeparatedSyntaxList <TNode>, string, int> indexOf) where TNode : SyntaxNode
        {
            XmlNodeSyntax firstElement = null;

            int firstIndex = -1;

            for (int i = 0; i < xmlNodes.Count; i++)
            {
                XmlElementInfo elementInfo = SyntaxInfo.XmlElementInfo(xmlNodes[i]);

                if (!elementInfo.Success)
                {
                    continue;
                }

                if (!elementInfo.HasTag(tag))
                {
                    firstIndex = -1;
                    continue;
                }

                XmlNodeSyntax element = elementInfo.Element;

                string name = (element.IsKind(SyntaxKind.XmlElement))
                    ? ((XmlElementSyntax)element).GetAttributeValue("name")
                    : ((XmlEmptyElementSyntax)element).GetAttributeValue("name");

                if (name == null)
                {
                    firstIndex = -1;
                    continue;
                }

                int index = indexOf(nodes, name);

                if (index == -1)
                {
                    ReportUnusedElement(context, element, i, xmlNodes);
                }
                else if (index < firstIndex)
                {
                    ReportDiagnosticIfNotSuppressed(context, DiagnosticRules.OrderElementsInDocumentationComment, firstElement);
                    return;
                }
                else
                {
                    firstElement = element;
                }

                firstIndex = index;
            }
        }
예제 #3
0
        private static void AnalyzeList(SyntaxNodeAnalysisContext context, XmlElementInfo elementInfo)
        {
            if (elementInfo.IsEmptyElement)
            {
                return;
            }

            var element = (XmlElementSyntax)elementInfo.Element;

            foreach (XmlNodeSyntax node in element.Content)
            {
                XmlElementInfo elementInfo2 = SyntaxInfo.XmlElementInfo(node);

                if (!elementInfo2.Success)
                {
                    continue;
                }

                if (elementInfo2.IsEmptyElement)
                {
                    continue;
                }

                if (!elementInfo2.HasLocalName("listheader", "item"))
                {
                    continue;
                }

                var element2 = (XmlElementSyntax)elementInfo2.Element;

                foreach (XmlNodeSyntax node2 in element2.Content)
                {
                    XmlElementInfo elementInfo3 = SyntaxInfo.XmlElementInfo(node2);

                    if (!elementInfo3.Success)
                    {
                        continue;
                    }

                    if (elementInfo3.IsEmptyElement)
                    {
                        continue;
                    }

                    if (elementInfo3.HasLocalName("term", "description"))
                    {
                        Analyze(context, elementInfo3);
                    }
                }
            }
        }
예제 #4
0
        public static void Analyze(SyntaxNodeAnalysisContext context, XmlElementInfo elementInfo)
        {
            if (elementInfo.IsEmptyElement)
            {
                return;
            }

            var element = (XmlElementSyntax)elementInfo.Element;

            foreach (XmlNodeSyntax node in element.Content)
            {
                XmlElementInfo elementInfo2 = SyntaxInfo.XmlElementInfo(node);

                if (elementInfo2.Success)
                {
                    switch (elementInfo2.GetTag())
                    {
                    case XmlTag.C:
                    {
                        AnalyzeCElement(context, elementInfo2);
                        break;
                    }

                    case XmlTag.Code:
                    {
                        AnalyzeCodeElement(context, elementInfo2);
                        break;
                    }

                    case XmlTag.List:
                    {
                        AnalyzeList(context, elementInfo2);
                        break;
                    }

                    case XmlTag.Para:
                    case XmlTag.ParamRef:
                    case XmlTag.See:
                    case XmlTag.TypeParamRef:
                    {
                        Analyze(context, elementInfo2);
                        break;
                    }
                    }
                }
            }
        }
예제 #5
0
        private static Task <Document> OrderElementsAsync(
            Document document,
            XmlNodeSyntax xmlNode,
            CancellationToken cancellationToken)
        {
            var documentationComment = (DocumentationCommentTriviaSyntax)xmlNode.Parent;

            SyntaxList <XmlNodeSyntax> content = documentationComment.Content;

            MemberDeclarationSyntax memberDeclaration = xmlNode.FirstAncestor <MemberDeclarationSyntax>();

            int firstIndex = content.IndexOf(xmlNode);

            SyntaxList <XmlNodeSyntax> newContent = GetNewContent();

            DocumentationCommentTriviaSyntax newDocumentationComment = documentationComment.WithContent(newContent);

            return(document.ReplaceNodeAsync(documentationComment, newDocumentationComment, cancellationToken));

            SyntaxList <XmlNodeSyntax> GetNewContent()
            {
                switch (SyntaxInfo.XmlElementInfo(xmlNode).GetElementKind())
                {
                case XmlElementKind.Param:
                {
                    SeparatedSyntaxList <ParameterSyntax> parameters = ParameterListInfo.Create(memberDeclaration).Parameters;

                    return(SortElements(parameters, content, firstIndex, XmlElementKind.Param, (nodes, name) => nodes.IndexOf(name)));
                }

                case XmlElementKind.TypeParam:
                {
                    SeparatedSyntaxList <TypeParameterSyntax> typeParameters = TypeParameterListInfo.Create(memberDeclaration).Parameters;

                    return(SortElements(typeParameters, content, firstIndex, XmlElementKind.TypeParam, (nodes, name) => nodes.IndexOf(name)));
                }

                default:
                {
                    throw new InvalidOperationException();
                }
                }
            }
        }
예제 #6
0
        private static bool IsMissing(DocumentationCommentTriviaSyntax documentationComment, TypeParameterSyntax typeParameter)
        {
            foreach (XmlNodeSyntax xmlNode in documentationComment.Content)
            {
                XmlElementInfo elementInfo = SyntaxInfo.XmlElementInfo(xmlNode);

                if (elementInfo.Success &&
                    !elementInfo.IsEmptyElement &&
                    elementInfo.HasTag(XmlTag.TypeParam))
                {
                    var element = (XmlElementSyntax)elementInfo.Element;

                    string value = element.GetAttributeValue("name");

                    if (value != null &&
                        string.Equals(typeParameter.Identifier.ValueText, value, StringComparison.Ordinal))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
예제 #7
0
        private static SyntaxList <XmlNodeSyntax> SortElements <TNode>(
            SeparatedSyntaxList <TNode> nodes,
            SyntaxList <XmlNodeSyntax> content,
            int firstIndex,
            XmlElementKind kind,
            Func <SeparatedSyntaxList <TNode>, string, int> indexOf) where TNode : SyntaxNode
        {
            var xmlNodes = new List <XmlNodeSyntax>();

            var ranks = new Dictionary <XmlNodeSyntax, int>();

            for (int i = firstIndex; i < content.Count; i++)
            {
                XmlElementInfo elementInfo = SyntaxInfo.XmlElementInfo(content[i]);

                if (elementInfo.Success)
                {
                    if (elementInfo.IsElementKind(kind))
                    {
                        XmlNodeSyntax element = elementInfo.Element;

                        string value = (element.IsKind(SyntaxKind.XmlElement))
                            ? ((XmlElementSyntax)element).GetAttributeValue("name")
                            : ((XmlEmptyElementSyntax)element).GetAttributeValue("name");

                        if (value != null)
                        {
                            ranks[element] = indexOf(nodes, value);
                        }
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                xmlNodes.Add(content[i]);
            }

            for (int i = 0; i < xmlNodes.Count - 1; i++)
            {
                for (int j = 0; j < xmlNodes.Count - i - 1; j++)
                {
                    XmlNodeSyntax node1 = xmlNodes[j];

                    if (ranks.TryGetValue(node1, out int rank1))
                    {
                        int k = j + 1;

                        while (k < xmlNodes.Count - i - 1)
                        {
                            XmlNodeSyntax node2 = xmlNodes[k];
                            if (ranks.TryGetValue(node2, out int rank2))
                            {
                                if (rank1 > rank2)
                                {
                                    xmlNodes[k] = node1;
                                    xmlNodes[j] = node2;
                                }

                                break;
                            }

                            k++;
                        }
                    }
                }
            }

            return(content.ReplaceRange(firstIndex, xmlNodes.Count, xmlNodes));
        }
예제 #8
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);
        }
예제 #9
0
        private static void AnalyzeSingleLineDocumentationCommentTrivia(SyntaxNodeAnalysisContext context)
        {
            var documentationComment = (DocumentationCommentTriviaSyntax)context.Node;

            if (!documentationComment.IsPartOfMemberDeclaration())
            {
                return;
            }

            bool?useCorrectDocumentationTagEnabled = null;
            var  containsInheritDoc       = false;
            var  containsIncludeOrExclude = false;
            var  containsSummaryElement   = false;
            var  containsContentElement   = false;
            var  isFirst = true;

            CancellationToken cancellationToken = context.CancellationToken;

            SyntaxList <XmlNodeSyntax> content = documentationComment.Content;

            for (int i = 0; i < content.Count; i++)
            {
                cancellationToken.ThrowIfCancellationRequested();

                XmlElementInfo info = SyntaxInfo.XmlElementInfo(content[i]);

                if (info.Success)
                {
                    switch (info.GetTag())
                    {
                    case XmlTag.Include:
                    case XmlTag.Exclude:
                    {
                        if (isFirst)
                        {
                            containsIncludeOrExclude = true;
                        }

                        break;
                    }

                    case XmlTag.InheritDoc:
                    {
                        containsInheritDoc = true;
                        break;
                    }

                    case XmlTag.Content:
                    {
                        containsContentElement = true;
                        break;
                    }

                    case XmlTag.Summary:
                    {
                        if (info.IsContentEmptyOrWhitespace)
                        {
                            ReportDiagnosticIfNotSuppressed(context, DiagnosticRules.AddSummaryToDocumentationComment, info.Element);
                        }

                        containsSummaryElement = true;

                        if (useCorrectDocumentationTagEnabled ??= DiagnosticRules.FixDocumentationCommentTag.IsEffective(context))
                        {
                            FixDocumentationCommentTagAnalysis.Analyze(context, info);
                        }

                        break;
                    }

                    case XmlTag.Example:
                    case XmlTag.Remarks:
                    case XmlTag.Returns:
                    case XmlTag.Value:
                    {
                        if (info.IsContentEmptyOrWhitespace)
                        {
                            ReportUnusedElement(context, info.Element, i, content);
                        }

                        if (useCorrectDocumentationTagEnabled ??= DiagnosticRules.FixDocumentationCommentTag.IsEffective(context))
                        {
                            FixDocumentationCommentTagAnalysis.Analyze(context, info);
                        }

                        break;
                    }

                    case XmlTag.Exception:
                    case XmlTag.List:
                    case XmlTag.Param:
                    case XmlTag.Permission:
                    case XmlTag.TypeParam:
                    {
                        if (useCorrectDocumentationTagEnabled ??= DiagnosticRules.FixDocumentationCommentTag.IsEffective(context))
                        {
                            FixDocumentationCommentTagAnalysis.Analyze(context, info);
                        }

                        break;
                    }

                    case XmlTag.C:
                    case XmlTag.Code:
                    case XmlTag.Para:
                    case XmlTag.ParamRef:
                    case XmlTag.See:
                    case XmlTag.SeeAlso:
                    case XmlTag.TypeParamRef:
                    {
                        break;
                    }

                    default:
                    {
                        Debug.Fail(info.GetTag().ToString());
                        break;
                    }
                    }

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

            if (containsInheritDoc ||
                containsIncludeOrExclude)
            {
                return;
            }

            if (!containsSummaryElement &&
                !containsContentElement)
            {
                ReportDiagnosticIfNotSuppressed(context, DiagnosticRules.AddSummaryElementToDocumentationComment, documentationComment);
            }

            SyntaxNode parent = documentationComment.ParentTrivia.Token.Parent;

            bool unusedElement = DiagnosticRules.UnusedElementInDocumentationComment.IsEffective(context);
            bool orderParams   = DiagnosticRules.OrderElementsInDocumentationComment.IsEffective(context);
            bool addParam      = DiagnosticRules.AddParamElementToDocumentationComment.IsEffective(context);
            bool addTypeParam  = DiagnosticRules.AddTypeParamElementToDocumentationComment.IsEffective(context);

            if (addParam ||
                orderParams ||
                unusedElement)
            {
                SeparatedSyntaxList <ParameterSyntax> parameters = CSharpUtility.GetParameters(
                    (parent is MemberDeclarationSyntax) ? parent : parent.Parent);

                if (addParam &&
                    parameters.Any())
                {
                    foreach (ParameterSyntax parameter in parameters)
                    {
                        if (IsMissing(documentationComment, parameter))
                        {
                            ReportDiagnostic(context, DiagnosticRules.AddParamElementToDocumentationComment, documentationComment);
                            break;
                        }
                    }
                }

                if (orderParams || unusedElement)
                {
                    Analyze(context, documentationComment.Content, parameters, XmlTag.Param, (nodes, name) => nodes.IndexOf(name));
                }
            }

            if (addTypeParam ||
                orderParams ||
                unusedElement)
            {
                SeparatedSyntaxList <TypeParameterSyntax> typeParameters = CSharpUtility.GetTypeParameters(
                    (parent is MemberDeclarationSyntax) ? parent : parent.Parent);

                if (addTypeParam &&
                    typeParameters.Any())
                {
                    foreach (TypeParameterSyntax typeParameter in typeParameters)
                    {
                        if (IsMissing(documentationComment, typeParameter))
                        {
                            ReportDiagnostic(context, DiagnosticRules.AddTypeParamElementToDocumentationComment, documentationComment);
                            break;
                        }
                    }
                }

                if (orderParams || unusedElement)
                {
                    Analyze(context, documentationComment.Content, typeParameters, XmlTag.TypeParam, (nodes, name) => nodes.IndexOf(name));
                }
            }
        }
예제 #10
0
        public static void AnalyzeSingleLineDocumentationCommentTrivia(SyntaxNodeAnalysisContext context)
        {
            var documentationComment = (DocumentationCommentTriviaSyntax)context.Node;

            if (!IsPartOfMemberDeclaration(documentationComment))
            {
                return;
            }

            bool containsInheritDoc       = false;
            bool containsIncludeOrExclude = false;
            bool containsSummaryElement   = false;
            bool isFirst = true;

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

                        break;
                    }

                    case XmlElementKind.InheritDoc:
                    {
                        containsInheritDoc = true;
                        break;
                    }

                    case XmlElementKind.Summary:
                    {
                        if (info.IsXmlEmptyElement || IsSummaryMissing((XmlElementSyntax)info.Element))
                        {
                            context.ReportDiagnostic(
                                DiagnosticDescriptors.AddSummaryToDocumentationComment,
                                info.Element);
                        }

                        containsSummaryElement = true;
                        break;
                    }
                    }

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

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

            if (!containsSummaryElement &&
                !containsInheritDoc &&
                !containsIncludeOrExclude)
            {
                context.ReportDiagnostic(
                    DiagnosticDescriptors.AddSummaryElementToDocumentationComment,
                    documentationComment);
            }
        }
예제 #11
0
        public static ImmutableArray <string> GetAttributeValues(DocumentationCommentTriviaSyntax comment, string elementName1, string elementName2, string attributeName)
        {
            HashSet <string> values = null;
            bool             containsIncludeOrExclude = false;
            bool             isFirst = true;

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

                        break;
                    }

                    case XmlElementKind.InheritDoc:
                    {
                        return(default(ImmutableArray <string>));
                    }

                    default:
                    {
                        if (!info.IsEmptyElement &&
                            info.IsLocalName(elementName1, elementName2))
                        {
                            string value = GetAttributeValue((XmlElementSyntax)info.Element, attributeName);

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

                        break;
                    }
                    }

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

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

            return(default(ImmutableArray <string>));
        }
        private static void AnalyzeSingleLineDocumentationCommentTrivia(SyntaxNodeAnalysisContext context)
        {
            var documentationComment = (DocumentationCommentTriviaSyntax)context.Node;

            if (!documentationComment.IsPartOfMemberDeclaration())
            {
                return;
            }

            bool containsInheritDoc       = false;
            bool containsIncludeOrExclude = false;
            bool containsSummaryElement   = false;
            bool containsContentElement   = false;
            bool isFirst = true;

            CancellationToken cancellationToken = context.CancellationToken;

            SyntaxList <XmlNodeSyntax> content = documentationComment.Content;

            for (int i = 0; i < content.Count; i++)
            {
                cancellationToken.ThrowIfCancellationRequested();

                XmlElementInfo info = SyntaxInfo.XmlElementInfo(content[i]);

                if (info.Success)
                {
                    switch (info.GetElementKind())
                    {
                    case XmlElementKind.Include:
                    case XmlElementKind.Exclude:
                    {
                        if (isFirst)
                        {
                            containsIncludeOrExclude = true;
                        }

                        break;
                    }

                    case XmlElementKind.InheritDoc:
                    {
                        containsInheritDoc = true;
                        break;
                    }

                    case XmlElementKind.Content:
                    {
                        containsContentElement = true;
                        break;
                    }

                    case XmlElementKind.Summary:
                    {
                        if (info.IsContentEmptyOrWhitespace)
                        {
                            ReportDiagnosticIfNotSuppressed(context, DiagnosticDescriptors.AddSummaryToDocumentationComment, info.Element);
                        }

                        containsSummaryElement = true;
                        break;
                    }

                    case XmlElementKind.Code:
                    case XmlElementKind.Example:
                    case XmlElementKind.Remarks:
                    case XmlElementKind.Returns:
                    case XmlElementKind.Value:
                    {
                        if (info.IsContentEmptyOrWhitespace)
                        {
                            ReportUnusedElement(context, info.Element, i, content);
                        }

                        break;
                    }
                    }

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

            if (containsInheritDoc ||
                containsIncludeOrExclude)
            {
                return;
            }

            if (!containsSummaryElement &&
                !containsContentElement)
            {
                ReportDiagnosticIfNotSuppressed(context, DiagnosticDescriptors.AddSummaryElementToDocumentationComment, documentationComment);
            }

            SyntaxNode parent = documentationComment.ParentTrivia.Token.Parent;

            bool unusedElement = !context.IsAnalyzerSuppressed(DiagnosticDescriptors.UnusedElementInDocumentationComment);
            bool orderParams   = !context.IsAnalyzerSuppressed(DiagnosticDescriptors.OrderElementsInDocumentationComment);
            bool addParam      = !context.IsAnalyzerSuppressed(DiagnosticDescriptors.AddParamElementToDocumentationComment);
            bool addTypeParam  = !context.IsAnalyzerSuppressed(DiagnosticDescriptors.AddTypeParamElementToDocumentationComment);

            if (addParam ||
                orderParams ||
                unusedElement)
            {
                SeparatedSyntaxList <ParameterSyntax> parameters = ParameterListInfo.Create(parent).Parameters;

                if (addParam &&
                    parameters.Any())
                {
                    foreach (ParameterSyntax parameter in parameters)
                    {
                        if (IsMissing(documentationComment, parameter))
                        {
                            ReportDiagnostic(context, DiagnosticDescriptors.AddParamElementToDocumentationComment, documentationComment);
                            break;
                        }
                    }
                }

                if (orderParams || unusedElement)
                {
                    Analyze(context, documentationComment.Content, parameters, XmlElementKind.Param, (nodes, name) => nodes.IndexOf(name));
                }
            }

            if (addTypeParam ||
                orderParams ||
                unusedElement)
            {
                SeparatedSyntaxList <TypeParameterSyntax> typeParameters = TypeParameterListInfo.Create(parent).Parameters;

                if (addTypeParam &&
                    typeParameters.Any())
                {
                    foreach (TypeParameterSyntax typeParameter in typeParameters)
                    {
                        if (IsMissing(documentationComment, typeParameter))
                        {
                            ReportDiagnostic(context, DiagnosticDescriptors.AddTypeParamElementToDocumentationComment, documentationComment);
                            break;
                        }
                    }
                }

                if (orderParams || unusedElement)
                {
                    Analyze(context, documentationComment.Content, typeParameters, XmlElementKind.TypeParam, (nodes, name) => nodes.IndexOf(name));
                }
            }
        }
예제 #13
0
        public static void AnalyzeSingleLineDocumentationCommentTrivia(SyntaxNodeAnalysisContext context)
        {
            var documentationComment = (DocumentationCommentTriviaSyntax)context.Node;

            if (!documentationComment.IsPartOfMemberDeclaration())
            {
                return;
            }

            bool containsInheritDoc       = false;
            bool containsIncludeOrExclude = false;
            bool containsSummaryElement   = false;
            bool containsContentElement   = false;
            bool isFirst = true;

            CancellationToken cancellationToken = context.CancellationToken;

            foreach (XmlNodeSyntax node in documentationComment.Content)
            {
                cancellationToken.ThrowIfCancellationRequested();

                XmlElementInfo info = SyntaxInfo.XmlElementInfo(node);
                if (info.Success)
                {
                    switch (info.GetElementKind())
                    {
                    case XmlElementKind.Include:
                    case XmlElementKind.Exclude:
                    {
                        if (isFirst)
                        {
                            containsIncludeOrExclude = true;
                        }

                        break;
                    }

                    case XmlElementKind.InheritDoc:
                    {
                        containsInheritDoc = true;
                        break;
                    }

                    case XmlElementKind.Content:
                    {
                        containsContentElement = true;
                        break;
                    }

                    case XmlElementKind.Summary:
                    {
                        if (info.IsContentEmptyOrWhitespace)
                        {
                            context.ReportDiagnostic(
                                DiagnosticDescriptors.AddSummaryToDocumentationComment,
                                info.Element);
                        }

                        containsSummaryElement = true;
                        break;
                    }

                    case XmlElementKind.Code:
                    case XmlElementKind.Example:
                    case XmlElementKind.Remarks:
                    case XmlElementKind.Returns:
                    case XmlElementKind.Value:
                    {
                        if (info.IsContentEmptyOrWhitespace)
                        {
                            context.ReportDiagnostic(
                                DiagnosticDescriptors.UnusedElementInDocumentationComment,
                                info.Element);
                        }

                        break;
                    }
                    }

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

            if (!containsSummaryElement &&
                !containsInheritDoc &&
                !containsIncludeOrExclude &&
                !containsContentElement)
            {
                context.ReportDiagnostic(
                    DiagnosticDescriptors.AddSummaryElementToDocumentationComment,
                    documentationComment);
            }
        }
예제 #14
0
        public static void Analyze(SyntaxNodeAnalysisContext context, XmlElementInfo elementInfo)
        {
            if (elementInfo.IsEmptyElement)
            {
                return;
            }

            var element = (XmlElementSyntax)elementInfo.Element;

            foreach (XmlNodeSyntax node in element.Content)
            {
                XmlElementInfo elementInfo2 = SyntaxInfo.XmlElementInfo(node);

                if (elementInfo2.Success)
                {
                    switch (elementInfo2.GetTag())
                    {
                    case XmlTag.C:
                    {
                        AnalyzeCElement(context, elementInfo2);
                        break;
                    }

                    case XmlTag.Code:
                    {
                        AnalyzeCodeElement(context, elementInfo2);
                        break;
                    }

                    case XmlTag.List:
                    {
                        AnalyzeList(context, elementInfo2);
                        break;
                    }

                    case XmlTag.Para:
                    case XmlTag.ParamRef:
                    case XmlTag.See:
                    case XmlTag.TypeParamRef:
                    {
                        Analyze(context, elementInfo2);
                        break;
                    }

                    case XmlTag.Content:
                    case XmlTag.Example:
                    case XmlTag.Exception:
                    case XmlTag.Exclude:
                    case XmlTag.Include:
                    case XmlTag.InheritDoc:
                    case XmlTag.Param:
                    case XmlTag.Permission:
                    case XmlTag.Remarks:
                    case XmlTag.Returns:
                    case XmlTag.SeeAlso:
                    case XmlTag.Summary:
                    case XmlTag.TypeParam:
                    case XmlTag.Value:
                    {
                        break;
                    }

                    default:
                    {
                        break;
                    }
                    }
                }
            }
        }