Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit

Permalink
Warn for boxing and delegate allocation for => syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
edespong committed Mar 30, 2018
1 parent 1bbe15d commit c3562bf
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -493,5 +493,73 @@ public void TypeConversionAllocation_DelegateAssignmentToReadonly_DoNotWarn()
Assert.AreEqual(1, info.Allocations.Count(x => x.Id == TypeConversionAllocationAnalyzer.ReadonlyMethodGroupAllocationRule.Id), snippet);
}
}

[TestMethod]
public void TypeConversionAllocation_ExpressionBodiedPropertyBoxing_WithBoxing() {
const string snippet = @"
class Program
{
object Obj => 1;
}
";

var analyzer = new TypeConversionAllocationAnalyzer();
var info = ProcessCode(analyzer, snippet, ImmutableArray.Create(
SyntaxKind.ArrowExpressionClause));
AssertEx.ContainsDiagnostic(info.Allocations, id: TypeConversionAllocationAnalyzer.ValueTypeToReferenceTypeConversionRule.Id, line: 4, character: 35);
}

[TestMethod]
public void TypeConversionAllocation_ExpressionBodiedPropertyBoxing_WithoutBoxing() {
const string snippet = @"
class Program
{
object Obj => 1.ToString();
}
";

var analyzer = new TypeConversionAllocationAnalyzer();
var info = ProcessCode(analyzer, snippet, ImmutableArray.Create(
SyntaxKind.ArrowExpressionClause));
Assert.AreEqual(0, info.Allocations.Count);
}

[TestMethod]
public void TypeConversionAllocation_ExpressionBodiedPropertyDelegate() {
const string snippet = @"
using System;
class Program
{
void Function(int i) { }
Action<int> Obj => Function;
}
";

var analyzer = new TypeConversionAllocationAnalyzer();
var info = ProcessCode(analyzer, snippet, ImmutableArray.Create(
SyntaxKind.ArrowExpressionClause));
AssertEx.ContainsDiagnostic(info.Allocations, id: TypeConversionAllocationAnalyzer.MethodGroupAllocationRule.Id, line: 7, character: 40);
}

[TestMethod]
[Description("Tests that an explicit delegate creation does not trigger HAA0603. " +
"It should be handled by HAA0502.")]
public void TypeConversionAllocation_ExpressionBodiedPropertyExplicitDelegate_NoWarning() {
const string snippet = @"
using System;
class Program
{
void Function(int i) { }
Action<int> Obj => new Action<int>(Function);
}
";

var analyzer = new TypeConversionAllocationAnalyzer();
var info = ProcessCode(analyzer, snippet, ImmutableArray.Create(
SyntaxKind.ArrowExpressionClause));
Assert.AreEqual(0, info.Allocations.Count);
}
}
}
33 changes: 30 additions & 3 deletions ClrHeapAllocationsAnalyzer/TypeConversionAllocationAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ public override void Initialize(AnalysisContext context)
SyntaxKind.ConditionalExpression,
SyntaxKind.ForEachStatement,
SyntaxKind.EqualsValueClause,
SyntaxKind.Argument
SyntaxKind.Argument,
SyntaxKind.ArrowExpressionClause
};
context.RegisterSyntaxNodeAction(AnalyzeNode, kinds);
}
Expand Down Expand Up @@ -102,6 +103,13 @@ private static void AnalyzeNode(SyntaxNodeAnalysisContext context)
CastExpressionCheck(node, semanticModel, reportDiagnostic, filePath, cancellationToken);
return;
}

// object Foo => 1
if (node is ArrowExpressionClauseSyntax)
{
ArrowExpressionCheck(node, semanticModel, assignedToReadonlyFieldOrProperty, reportDiagnostic, filePath, cancellationToken);
return;
}
}

private static void ReturnStatementExpressionCheck(SyntaxNode node, SemanticModel semanticModel, Action<Diagnostic> reportDiagnostic, string filePath, CancellationToken cancellationToken)
Expand Down Expand Up @@ -210,6 +218,18 @@ private static void EqualsValueClauseCheck(SyntaxNode node, SemanticModel semant
}
}


private static void ArrowExpressionCheck(SyntaxNode node, SemanticModel semanticModel, bool isAssignmentToReadonly, Action<Diagnostic> reportDiagnostic, string filePath, CancellationToken cancellationToken)
{
var syntax = node as ArrowExpressionClauseSyntax;

var typeInfo = semanticModel.GetTypeInfo(syntax.Expression, cancellationToken);
var conversionInfo = semanticModel.GetConversion(syntax.Expression, cancellationToken);
CheckTypeConversion(conversionInfo, reportDiagnostic, syntax.Expression.GetLocation(), filePath);
CheckDelegateCreation(syntax, typeInfo, semanticModel, false, reportDiagnostic,
syntax.Expression.GetLocation(), filePath, cancellationToken);
}

private static void CheckTypeConversion(Conversion conversionInfo, Action<Diagnostic> reportDiagnostic, Location location, string filePath)
{
if (conversionInfo.IsBoxing)
Expand All @@ -236,8 +256,7 @@ node is AnonymousMethodExpressionSyntax || node is ObjectCreationExpressionSynta
{
if (node.IsKind(SyntaxKind.IdentifierName))
{
if (semanticModel.GetSymbolInfo(node, cancellationToken).Symbol is IMethodSymbol)
{
if (semanticModel.GetSymbolInfo(node, cancellationToken).Symbol is IMethodSymbol) {
reportDiagnostic(Diagnostic.Create(MethodGroupAllocationRule, location, EmptyMessageArgs));
HeapAllocationAnalyzerEventSource.Logger.MethodGroupAllocation(filePath);
}
Expand All @@ -258,6 +277,14 @@ node is AnonymousMethodExpressionSyntax || node is ObjectCreationExpressionSynta
HeapAllocationAnalyzerEventSource.Logger.MethodGroupAllocation(filePath);
}
}
}
else if (node is ArrowExpressionClauseSyntax)
{
var arrowClause = node as ArrowExpressionClauseSyntax;
if (semanticModel.GetSymbolInfo(arrowClause.Expression, cancellationToken).Symbol is IMethodSymbol) {
reportDiagnostic(Diagnostic.Create(MethodGroupAllocationRule, location, EmptyMessageArgs));
HeapAllocationAnalyzerEventSource.Logger.MethodGroupAllocation(filePath);
}
}
}

Expand Down

0 comments on commit c3562bf

Please sign in to comment.