Skip to content

Commit

Permalink
Fix S6966 FP: Don't raise on XmlReader and XmlWriter methods (#9364)
Browse files Browse the repository at this point in the history
  • Loading branch information
mary-georgiou-sonarsource authored May 30, 2024
1 parent 2983749 commit bd737fd
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 6 deletions.
10 changes: 6 additions & 4 deletions analyzers/src/SonarAnalyzer.CSharp/Rules/UseAwaitableMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ public sealed class UseAwaitableMethod : SonarDiagnosticAnalyzer
{
private const string DiagnosticId = "S6966";
private const string MessageFormat = "Await {0} instead.";
private static readonly string[] ExcludedMethodNamesAddAddRange = ["Add", "AddRange"];
private static readonly string[] ExcludedMethodNames = ["Add", "AddRange"];
private static readonly ImmutableArray<KnownType> ExcludedTypes = ImmutableArray.Create(KnownType.System_Xml_XmlWriter, KnownType.System_Xml_XmlReader);

private static readonly DiagnosticDescriptor Rule = DescriptorFactory.Create(DiagnosticId, MessageFormat);

Expand Down Expand Up @@ -92,8 +93,8 @@ private static ImmutableArray<Func<IMethodSymbol, bool>> BuildExclusions(Compila
var exclusions = ImmutableArray.CreateBuilder<Func<IMethodSymbol, bool>>();
if (compilation.GetTypeByMetadataName(KnownType.Microsoft_EntityFrameworkCore_DbSet_TEntity) is not null)
{
exclusions.Add(x => x.IsAny(KnownType.Microsoft_EntityFrameworkCore_DbSet_TEntity, ExcludedMethodNamesAddAddRange)); // https://github.com/SonarSource/sonar-dotnet/issues/9269
exclusions.Add(x => x.IsAny(KnownType.Microsoft_EntityFrameworkCore_DbContext, ExcludedMethodNamesAddAddRange)); // https://github.com/SonarSource/sonar-dotnet/issues/9269
exclusions.Add(x => x.IsAny(KnownType.Microsoft_EntityFrameworkCore_DbSet_TEntity, ExcludedMethodNames)); // https://github.com/SonarSource/sonar-dotnet/issues/9269
exclusions.Add(x => x.IsAny(KnownType.Microsoft_EntityFrameworkCore_DbContext, ExcludedMethodNames)); // https://github.com/SonarSource/sonar-dotnet/issues/9269
}
if (compilation.GetTypeByMetadataName(KnownType.FluentValidation_IValidator) is not null)
{
Expand All @@ -115,7 +116,8 @@ private static ImmutableArray<ISymbol> FindAwaitableAlternatives(WellKnownExtens
&& invocationExpression.EnclosingScope() is { } scope
&& IsAsyncCodeBlock(scope)
&& semanticModel.GetSymbolInfo(invocationExpression, cancel).Symbol is IMethodSymbol { MethodKind: not MethodKind.DelegateInvoke } methodSymbol
&& !methodSymbol.IsAwaitableNonDynamic() // The invoked method returns something awaitable (but it isn't awaited).
&& !(methodSymbol.IsAwaitableNonDynamic() // The invoked method returns something awaitable (but it isn't awaited).
|| methodSymbol.ContainingType.DerivesFromAny(ExcludedTypes))
&& !exclusions.Any(x => x(methodSymbol)))
{
// Perf: Before doing (expensive) speculative re-binding in SpeculativeBindCandidates, we check if there is an "..Async()" alternative in scope.
Expand Down
3 changes: 2 additions & 1 deletion analyzers/src/SonarAnalyzer.Common/Helpers/KnownType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,7 @@ public sealed partial class KnownType
public static readonly KnownType System_Windows_Markup_XmlnsPrefixAttribute = new("System.Windows.Markup.XmlnsPrefixAttribute");
public static readonly KnownType System_Windows_Markup_XmlnsDefinitionAttribute = new("System.Windows.Markup.XmlnsDefinitionAttribute");
public static readonly KnownType System_Windows_Markup_XmlnsCompatibleWithAttribute = new("System.Windows.Markup.XmlnsCompatibleWithAttribute");
public static readonly KnownType System_Xml_Resolvers_XmlPreloadedResolver = new("System.Xml.Resolvers.XmlPreloadedResolver");
public static readonly KnownType System_Xml_Serialization_XmlElementAttribute = new("System.Xml.Serialization.XmlElementAttribute");
public static readonly KnownType System_Xml_XmlDocument = new("System.Xml.XmlDocument");
public static readonly KnownType System_Xml_XmlDataDocument = new("System.Xml.XmlDataDocument");
Expand All @@ -633,7 +634,7 @@ public sealed partial class KnownType
public static readonly KnownType System_Xml_XmlReaderSettings = new("System.Xml.XmlReaderSettings");
public static readonly KnownType System_Xml_XmlUrlResolver = new("System.Xml.XmlUrlResolver");
public static readonly KnownType System_Xml_XmlTextReader = new("System.Xml.XmlTextReader");
public static readonly KnownType System_Xml_Resolvers_XmlPreloadedResolver = new("System.Xml.Resolvers.XmlPreloadedResolver");
public static readonly KnownType System_Xml_XmlWriter = new("System.Xml.XmlWriter");
public static readonly KnownType Void = new("System.Void");
public static readonly KnownType NSubstitute_SubstituteExtensions = new("NSubstitute.SubstituteExtensions");
public static readonly KnownType NSubstitute_Received = new("NSubstitute.Received");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ async Task MethodInvocations()
{
ActionProperty(); // Compliant;
}
}
}
""").VerifyNoIssues();

[TestMethod]
Expand All @@ -75,6 +75,50 @@ public void UseAwaitableMethod_FluentValidation() =>
.AddPaths("UseAwaitableMethod_FluentValidation.cs")
.Verify();

[TestMethod]
public void UseAwaitableMethod_ExcludeXmlReaderAndWriter() =>
builder
.AddReferences(MetadataReferenceFacade.SystemXml)
.AddSnippet("""
using System.IO;
using System.Threading.Tasks;
using System.Xml;
public class Test
{
async Task TestReader(Stream stream)
{
using (XmlReader reader = XmlReader.Create(stream))
{
reader.Read(); // Compliant, we don't raise for XmlReader methods https://github.com/SonarSource/sonar-dotnet/issues/9336
reader.ReadContentAs(typeof(int), null); // Compliant
reader.MoveToContent(); // Compliant
reader.ReadContentAsBase64(null, 0, 0); // Compliant
reader.ReadContentAsBinHex(null, 0, 0); // Compliant
reader.ReadContentAsObject(); // Compliant
reader.ReadContentAsString(); // Compliant
reader.ReadInnerXml(); // Compliant
reader.ReadOuterXml(); // Compliant
reader.ReadValueChunk(null, 0, 0); // Compliant
}
using (XmlWriter writer = XmlWriter.Create(stream))
{
writer.WriteStartElement("pf", "root", "http://ns"); // Compliant, we don't raise for XmlWriter methods https://github.com/SonarSource/sonar-dotnet/issues/9336
writer.WriteStartElement(null, "sub", null); // Compliant
writer.WriteAttributeString(null, "att", null, "val"); // Compliant
writer.WriteString("text"); // Compliant
writer.WriteEndElement(); // Compliant
writer.WriteProcessingInstruction("pName", "pValue"); // Compliant
writer.WriteComment("cValue"); // Compliant
writer.WriteCData("cdata value"); // Compliant
writer.WriteEndElement(); // Compliant
writer.Flush(); // Compliant
}
}
}
""").VerifyNoIssues();

#if NET
[TestMethod]
public void UseAwaitableMethod_CSharp9() =>
Expand Down

0 comments on commit bd737fd

Please sign in to comment.