/// <inheritdoc/>
        protected override void HandleXmlElement(SyntaxNodeAnalysisContext context, IEnumerable <XmlNodeSyntax> syntaxList, params Location[] diagnosticLocations)
        {
            var node       = context.Node;
            var identifier = GetIdentifier(node);

            bool supportedIdentifier = identifier != null;

            if (!supportedIdentifier)
            {
                return;
            }

            var identifierLocation = identifier.Value.GetLocation();
            var parameterList      = GetParameters(node)?.ToImmutableArray();

            bool hasNoParameters = !parameterList?.Any() ?? false;

            if (hasNoParameters)
            {
                return;
            }

            var parentParameters = parameterList.Value;

            var index = 0;

            foreach (var syntax in syntaxList)
            {
                var nameAttributeSyntax = XmlCommentHelper.GetFirstAttributeOrDefault <XmlNameAttributeSyntax>(syntax);
                var nameAttributeText   = nameAttributeSyntax?.Identifier?.Identifier.ValueText;
                var location            = nameAttributeSyntax?.Identifier?.Identifier.GetLocation();

                // Make sure we ignore violations that should be reported by SA1613 instead.
                if (string.IsNullOrWhiteSpace(nameAttributeText))
                {
                    return;
                }

                var parentParameter = parentParameters.FirstOrDefault(s => s.Identifier.Text == nameAttributeText);
                if (parentParameter == null)
                {
                    context.ReportDiagnostic(Diagnostic.Create(MissingParameterDescriptor, location ?? identifierLocation, nameAttributeText));
                }
                else if (parentParameters.Length <= index || parentParameters[index] != parentParameter)
                {
                    context.ReportDiagnostic(
                        Diagnostic.Create(
                            OrderDescriptor,
                            location ?? identifierLocation,
                            nameAttributeText,
                            parentParameters.IndexOf(parentParameter) + 1));
                }

                index++;
            }
        }
Beispiel #2
0
        private static void HandleElement(SyntaxNodeAnalysisContext context, XmlNodeSyntax element, XmlNameSyntax name, Location alternativeDiagnosticLocation)
        {
            if (string.Equals(name.ToString(), XmlCommentHelper.TypeParamXmlTag))
            {
                var nameAttribute = XmlCommentHelper.GetFirstAttributeOrDefault <XmlNameAttributeSyntax>(element);

                if (string.IsNullOrWhiteSpace(nameAttribute?.Identifier?.Identifier.ValueText))
                {
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, nameAttribute?.GetLocation() ?? alternativeDiagnosticLocation));
                }
            }
        }
Beispiel #3
0
        /// <inheritdoc/>
        protected override void HandleXmlElement(SyntaxNodeAnalysisContext context, bool needsComment, IEnumerable <XmlNodeSyntax> syntaxList, params Location[] diagnosticLocations)
        {
            foreach (var syntax in syntaxList)
            {
                var nameParameter  = XmlCommentHelper.GetFirstAttributeOrDefault <XmlNameAttributeSyntax>(syntax);
                var parameterValue = nameParameter?.Identifier?.Identifier.ValueText;

                if (string.IsNullOrWhiteSpace(parameterValue))
                {
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, nameParameter?.GetLocation() ?? syntax.GetLocation()));
                }
            }
        }
Beispiel #4
0
        private static void HandleElement(SyntaxNodeAnalysisContext context, XmlNodeSyntax element, XmlNameSyntax name, Location alternativeDiagnosticLocation)
        {
            if (string.Equals(name.ToString(), XmlCommentHelper.ParamTag))
            {
                var nameAttribute = XmlCommentHelper.GetFirstAttributeOrDefault <XmlNameAttributeSyntax>(element);

                // Make sure we ignore violations that should be reported by SA1613 instead.
                if (!string.IsNullOrWhiteSpace(nameAttribute?.Identifier?.Identifier.ValueText) && ParentElementHasParameter(element, nameAttribute.Identifier.Identifier.ValueText) == false)
                {
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, nameAttribute?.Identifier?.GetLocation() ?? alternativeDiagnosticLocation));
                }
            }
        }
        private static void HandleElement(SyntaxNodeAnalysisContext context, XmlNodeSyntax element, ImmutableArray <string> parentParameters, int index, Location alternativeDiagnosticLocation)
        {
            var nameAttribute = XmlCommentHelper.GetFirstAttributeOrDefault <XmlNameAttributeSyntax>(element);

            // Make sure we ignore violations that should be reported by SA1613 instead.
            if (string.IsNullOrWhiteSpace(nameAttribute?.Identifier?.Identifier.ValueText))
            {
                return;
            }

            if (!parentParameters.Contains(nameAttribute.Identifier.Identifier.ValueText))
            {
                context.ReportDiagnostic(Diagnostic.Create(MissingParameterDescriptor, nameAttribute?.Identifier?.GetLocation() ?? alternativeDiagnosticLocation, nameAttribute.Identifier.Identifier.ValueText));
            }
            else if (parentParameters.Length <= index || parentParameters[index] != nameAttribute.Identifier.Identifier.ValueText)
            {
                context.ReportDiagnostic(Diagnostic.Create(OrderDescriptor, nameAttribute?.Identifier?.GetLocation() ?? alternativeDiagnosticLocation,
                                                           nameAttribute.Identifier.Identifier.ValueText, parentParameters.IndexOf(nameAttribute.Identifier.Identifier.ValueText) + 1));
            }
        }
        private static bool SeeTagIsCorrect(SyntaxNodeAnalysisContext context, XmlEmptyElementSyntax classReferencePart, BaseMethodDeclarationSyntax constructorDeclarationSyntax)
        {
            XmlCrefAttributeSyntax crefAttribute = XmlCommentHelper.GetFirstAttributeOrDefault <XmlCrefAttributeSyntax>(classReferencePart);
            CrefSyntax             crefSyntax    = crefAttribute?.Cref;

            if (crefAttribute == null)
            {
                return(false);
            }

            SemanticModel semanticModel = context.SemanticModel;

            if (!(semanticModel.GetSymbolInfo(crefSyntax, context.CancellationToken).Symbol is INamedTypeSymbol actualSymbol))
            {
                return(false);
            }

            INamedTypeSymbol expectedSymbol = semanticModel.GetDeclaredSymbol(constructorDeclarationSyntax.Parent, context.CancellationToken) as INamedTypeSymbol;

            return(Equals(actualSymbol.OriginalDefinition, expectedSymbol));
        }
        private static void HandleDeclaration(SyntaxNodeAnalysisContext context, SyntaxNode node, TypeParameterListSyntax typeParameterList)
        {
            if (typeParameterList == null)
            {
                // The node does not have a type parameter list
                return;
            }

            var documentation = node.GetDocumentationCommentTriviaSyntax();

            if (documentation == null)
            {
                // Don't report if the documentation is missing
                return;
            }

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

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

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

                rawDocumentation = declaration.GetDocumentationCommentXml(expandIncludes: true, cancellationToken: context.CancellationToken);
                var completeDocumentation = XElement.Parse(rawDocumentation, LoadOptions.None);
                if (completeDocumentation.Nodes().OfType <XElement>().Any(element => element.Name == XmlCommentHelper.InheritdocXmlTag))
                {
                    // Ignore nodes with an <inheritdoc/> tag in the included XML.
                    return;
                }

                var typeParameterAttributes = completeDocumentation.Nodes()
                                              .OfType <XElement>()
                                              .Where(element => element.Name == XmlCommentHelper.TypeParamXmlTag)
                                              .ToImmutableArray();

                // Check based on the documented type parameters, as we must detect scenarios where there are too many type parameters documented.
                // It is not necessary to detect missing type parameter documentation, this belongs to SA1618.
                for (var i = 0; i < typeParameterAttributes.Length; i++)
                {
                    var documentedParameterName = typeParameterAttributes[i].Attribute(XmlCommentHelper.NameArgumentName)?.Value;
                    HandleTypeParamElement(context, documentedParameterName, i, typeParameterList, includeElement.GetLocation());

                    if (XmlCommentHelper.IsConsideredEmpty(typeParameterAttributes[i]))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                SA1622Descriptor,
                                includeElement.GetLocation()));
                    }
                }
            }
            else
            {
                var typeParameterTags = documentation.Content.GetXmlElements(XmlCommentHelper.TypeParamXmlTag)
                                        .ToImmutableArray();

                // Check based on the documented type parameters, as we must detect scenarios where there are too many type parameters documented.
                // It is not necessary to detect missing type parameter documentation, this belongs to SA1618.
                for (var i = 0; i < typeParameterTags.Length; i++)
                {
                    var nameAttribute           = XmlCommentHelper.GetFirstAttributeOrDefault <XmlNameAttributeSyntax>(typeParameterTags[i]);
                    var documentedParameterName = nameAttribute?.Identifier?.Identifier.ValueText;

                    var location = nameAttribute?.Identifier?.GetLocation() ?? typeParameterTags[i].GetLocation();
                    HandleTypeParamElement(context, documentedParameterName, i, typeParameterList, location);

                    if (XmlCommentHelper.IsConsideredEmpty(typeParameterTags[i], true))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                SA1622Descriptor,
                                typeParameterTags[i].GetLocation()));
                    }
                }
            }
        }
Beispiel #8
0
        protected override void HandleXmlElement(SyntaxNodeAnalysisContext context, StyleCopSettings settings, bool needsComment, IEnumerable <XmlNodeSyntax> syntaxList, params Location[] diagnosticLocations)
        {
            var node       = context.Node;
            var identifier = GetIdentifier(node);

            bool supportedIdentifier = identifier != null;

            if (!supportedIdentifier)
            {
                return;
            }

            var parameterList = GetParameters(node)?.ToImmutableArray();

            bool hasNoParameters = !parameterList?.Any() ?? false;

            if (hasNoParameters)
            {
                return;
            }

            var parentParameters = parameterList.Value;

            var index = 0;

            foreach (var syntax in syntaxList)
            {
                var nameAttributeSyntax = XmlCommentHelper.GetFirstAttributeOrDefault <XmlNameAttributeSyntax>(syntax);
                var nameAttributeText   = nameAttributeSyntax?.Identifier?.Identifier.ValueText;

                // Make sure we ignore violations that should be reported by SA1613 instead.
                if (string.IsNullOrWhiteSpace(nameAttributeText))
                {
                    return;
                }

                var location = nameAttributeSyntax.Identifier.Identifier.GetLocation();

                var parentParameter = parentParameters.FirstOrDefault(s => s.Identifier.ValueText == nameAttributeText);
                if (parentParameter == null)
                {
                    context.ReportDiagnostic(Diagnostic.Create(MissingParameterDescriptor, location, nameAttributeText));
                }
                else
                {
                    if (!needsComment)
                    {
                        // Parameter documentation is allowed to be omitted, so skip parameters for which there is no
                        // documentation.
                        while (index < parentParameters.Length && parentParameters[index] != parentParameter)
                        {
                            index++;
                        }
                    }

                    if (parentParameters.Length <= index || parentParameters[index] != parentParameter)
                    {
#pragma warning disable RS1005 // ReportDiagnostic invoked with an unsupported DiagnosticDescriptor (https://github.com/dotnet/roslyn-analyzers/issues/4103)
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                OrderDescriptor,
                                location,
                                nameAttributeText,
                                parentParameters.IndexOf(parentParameter) + 1));
#pragma warning restore RS1005 // ReportDiagnostic invoked with an unsupported DiagnosticDescriptor
                    }
                }

                index++;
            }
        }