/// <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++; } }
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)); } } }
/// <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())); } } }
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())); } } } }
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++; } }