Skip to content

Commit

Permalink
MA0042 skips MemoryStream when type is explicit
Browse files Browse the repository at this point in the history
  • Loading branch information
meziantou committed Nov 26, 2024
1 parent f255a66 commit 1b0e98c
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 8 deletions.
20 changes: 13 additions & 7 deletions src/Meziantou.Analyzer/Internals/SymbolExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,17 @@ public static IEnumerable<ISymbol> GetAllMembers(this ITypeSymbol? symbol)
}
}

public static IEnumerable<ISymbol> GetAllMembers(this ITypeSymbol? symbol, string name)
{
while (symbol is not null)
{
foreach (var member in symbol.GetMembers(name))
yield return member;

symbol = symbol.BaseType;
}
}

public static bool IsTopLevelStatement(this ISymbol symbol, CancellationToken cancellationToken)
{
if (symbol.DeclaringSyntaxReferences.Length == 0)
Expand All @@ -102,12 +113,7 @@ public static bool IsTopLevelStatement(this ISymbol symbol, CancellationToken ca

public static bool IsTopLevelStatementsEntryPointMethod([NotNullWhen(true)] this IMethodSymbol? methodSymbol)
{
return methodSymbol?.IsStatic == true && methodSymbol.Name switch
{
"$Main" => true,
"<Main>$" => true,
_ => false
};
return methodSymbol is { IsStatic: true, Name: "$Main" or "<Main>$" };
}

public static bool IsTopLevelStatementsEntryPointType([NotNullWhen(true)] this INamedTypeSymbol? typeSymbol)
Expand All @@ -117,7 +123,7 @@ public static bool IsTopLevelStatementsEntryPointType([NotNullWhen(true)] this I

foreach (var member in typeSymbol.GetMembers())
{
if (member.Kind == SymbolKind.Method)
if (member.Kind is SymbolKind.Method)
{
var method = (IMethodSymbol)member;
if (method.IsTopLevelStatementsEntryPointMethod())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ public Context(Compilation compilation)
ConsoleErrorAndOutSymbols = [];
}

MemoryStreamSymbol = compilation.GetBestTypeByMetadataName("System.IO.MemoryStream");
ProcessSymbol = compilation.GetBestTypeByMetadataName("System.Diagnostics.Process");
CancellationTokenSymbol = compilation.GetBestTypeByMetadataName("System.Threading.CancellationToken");
ObsoleteAttributeSymbol = compilation.GetBestTypeByMetadataName("System.ObsoleteAttribute");
Expand Down Expand Up @@ -115,6 +116,7 @@ public Context(Compilation compilation)
_taskAwaiterLikeSymbols = [.. taskAwaiterLikeSymbols];
}

private ISymbol? MemoryStreamSymbol { get; }
private ISymbol? ProcessSymbol { get; }
private ISymbol[] ConsoleErrorAndOutSymbols { get; }
private INamedTypeSymbol? CancellationTokenSymbol { get; }
Expand Down Expand Up @@ -377,7 +379,7 @@ private static bool CanBeAsync(IOperation operation)

private bool HasDisposeAsyncMethod(INamedTypeSymbol symbol)
{
var members = symbol.GetMembers("DisposeAsync");
var members = symbol.GetAllMembers("DisposeAsync");
foreach (var member in members.OfType<IMethodSymbol>())
{
if (member.Parameters.Length != 0)
Expand All @@ -403,6 +405,10 @@ private bool CanBeAwaitUsing(IOperation operation)
if (operation.GetActualType() is not INamedTypeSymbol type)
return false;

// using var ms = new MemoryStream();
if (operation is IObjectCreationOperation objectCreationOperation && objectCreationOperation.Type.IsEqualTo(MemoryStreamSymbol))
return false;

return HasDisposeAsyncMethod(type);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -927,4 +927,16 @@ public void A()
""")
.ValidateAsync();
}

[Fact]
public async Task UsingNewMemoryStream()
{
await CreateProjectBuilder()
.WithOutputKind(Microsoft.CodeAnalysis.OutputKind.ConsoleApplication)
.WithTargetFramework(TargetFramework.Net8_0)
.WithSourceCode("""
using var ms = new System.IO.MemoryStream();
""")
.ValidateAsync();
}
}

0 comments on commit 1b0e98c

Please sign in to comment.