public void TypeConversionAllocation_EqualsValueClauseSyntax() { // for (object i = 0;;) var sampleProgram = @"using System; for (object i = 0;;) // Allocation { } for (int i = 0;;) // NO Allocation { }"; var analyser = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyser, sampleProgram, ImmutableArray.Create( SyntaxKind.SimpleAssignmentExpression, SyntaxKind.ReturnStatement, SyntaxKind.YieldReturnStatement, SyntaxKind.CastExpression, SyntaxKind.AsExpression, SyntaxKind.CoalesceExpression, SyntaxKind.ConditionalExpression, SyntaxKind.ForEachStatement, SyntaxKind.EqualsValueClause, SyntaxKind.Argument)); Assert.AreEqual(1, info.Allocations.Count); // Diagnostic: (3,17): warning HeapAnalyzerBoxingRule: Value type to reference type conversion causes boxing at call site (here), and unboxing at the callee-site. Consider using generics if applicable AssertEx.ContainsDiagnostic(info.Allocations, id: TypeConversionAllocationAnalyzer.ValueTypeToReferenceTypeConversionRule.Id, line: 3, character: 17); }
public void Creating_delegate_from_value_type_instance_method() { var @script = @"using System; struct S { public void M() {} } Action box = new S().M;"; var analyser = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyser, @script, ImmutableArray.Create( SyntaxKind.SimpleAssignmentExpression, SyntaxKind.ReturnStatement, SyntaxKind.YieldReturnStatement, SyntaxKind.CastExpression, SyntaxKind.AsExpression, SyntaxKind.CoalesceExpression, SyntaxKind.ConditionalExpression, SyntaxKind.ForEachStatement, SyntaxKind.EqualsValueClause, SyntaxKind.Argument)); Assert.Equal(2, info.Allocations.Count); // Diagnostic: (3,30): warning HeapAnalyzerMethodGroupAllocationRule: This will allocate a delegate instance AssertEx.ContainsDiagnostic(info.Allocations, TypeConversionAllocationAnalyzer.MethodGroupAllocationRule.Id, line: 3, character: 30); // Diagnostic: (3,30): warning HeapAnalyzerDelegateOnStructRule: Struct instance method being used for delegate creation, this will result in a boxing instruction AssertEx.ContainsDiagnostic(info.Allocations, TypeConversionAllocationAnalyzer.DelegateOnStructInstanceRule.Id, line: 3, character: 30); }
public void TypeConversionAllocation_EqualsValueClause_ExplicitMethodGroupAllocation_Bug() { // See https://github.com/mjsabby/RoslynClrHeapAllocationAnalyzer/issues/2 var sampleProgram = @"using System; public class MyClass { public void Testing() { Action methodGroup = this.Method; } private void Method() { } } public struct MyStruct { public void Testing() { Action methodGroup = this.Method; } private void Method() { } }"; var analyser = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyser, sampleProgram, ImmutableArray.Create(SyntaxKind.EqualsValueClause)); Assert.AreEqual(3, info.Allocations.Count); }
public void TypeConversionAllocation_ArgumentSyntax() { var sampleProgram = @"using System; var result = fooObjCall(10); // Allocation var temp = new MyObject(10); // Allocation private string fooObjCall(object obj) { return obj.ToString(); } public class MyObject { private Object Obj; public MyObject(object obj) { this.Obj = obj; } }"; var analyser = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyser, sampleProgram, ImmutableArray.Create(SyntaxKind.Argument)); Assert.AreEqual(2, info.Allocations.Count); // Diagnostic: (3,25): warning HeapAnalyzerBoxingRule: Value type to reference type conversion causes boxing at call site (here), and unboxing at the callee-site. Consider using generics if applicable *** AssertEx.ContainsDiagnostic(info.Allocations, id: TypeConversionAllocationAnalyzer.ValueTypeToReferenceTypeConversionRule.Id, line: 3, character: 25); // Diagnostic: (4,25): warning HeapAnalyzerBoxingRule: Value type to reference type conversion causes boxing at call site (here), and unboxing at the callee-site. Consider using generics if applicable *** AssertEx.ContainsDiagnostic(info.Allocations, id: TypeConversionAllocationAnalyzer.ValueTypeToReferenceTypeConversionRule.Id, line: 4, character: 25); }
public void TypeConversionAllocation_DoNotReportInlineDelegateAsStructInstanceMethods() { const string snippet = @" using System; public struct MyStruct { public void Testing() { var ints = new[] { 5, 4, 3, 2, 1 }; Array.Sort(ints, delegate(int x, int y) { return x - y; }); Array.Sort(ints, (x, y) => x - y); DoSomething(() => throw new Exception()); DoSomething(delegate() { throw new Exception(); }); } private static void DoSomething(Action action) { } } "; var analyzer = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyzer, snippet, ImmutableArray.Create(SyntaxKind.Argument)); AssertEx.ContainsNoDiagnostic(info.Allocations, TypeConversionAllocationAnalyzer.DelegateOnStructInstanceRule.Id, 6, 26); AssertEx.ContainsNoDiagnostic(info.Allocations, TypeConversionAllocationAnalyzer.DelegateOnStructInstanceRule.Id, 7, 26); AssertEx.ContainsNoDiagnostic(info.Allocations, TypeConversionAllocationAnalyzer.DelegateOnStructInstanceRule.Id, 8, 26); AssertEx.ContainsNoDiagnostic(info.Allocations, TypeConversionAllocationAnalyzer.DelegateOnStructInstanceRule.Id, 9, 26); }
public void TypeConversionAllocation_InterpolatedStringWithString_NoWarning() { var sampleProgram = @"string s = $""{1.ToString()}"";"; var analyser = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyser, sampleProgram, ImmutableArray.Create(SyntaxKind.Interpolation)); Assert.Empty(info.Allocations); }
public void TypeConversionAllocation_ArgumentSyntax_WithDelegates() { var sampleProgram = @"using System; public class MyClass { public void Testing() { var @class = new MyClass(); @class.ProcessFunc(fooObjCall); // implicit, so Allocation @class.ProcessFunc(new Func<object, string>(fooObjCall)); // Explicit, so NO Allocation } public void ProcessFunc(Func<object, string> func) { } private string fooObjCall(object obj) { return obj.ToString(); } } public struct MyStruct { public void Testing() { var @struct = new MyStruct(); @struct.ProcessFunc(fooObjCall); // implicit, so Allocation @struct.ProcessFunc(new Func<object, string>(fooObjCall)); // Explicit, so just warn for boxing } public void ProcessFunc(Func<object, string> func) { } private string fooObjCall(object obj) { return obj.ToString(); } }"; var analyser = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyser, sampleProgram, ImmutableArray.Create(SyntaxKind.Argument)); Assert.AreEqual(4, info.Allocations.Count); // Diagnostic: (8,28): warning HeapAnalyzerMethodGroupAllocationRule: This will allocate a delegate instance AssertEx.ContainsDiagnostic(info.Allocations, id: AllocationRules.MethodGroupAllocationRule.Id, line: 8, character: 28); // Diagnostic: (27,29): warning HeapAnalyzerMethodGroupAllocationRule: This will allocate a delegate instance AssertEx.ContainsDiagnostic(info.Allocations, id: AllocationRules.MethodGroupAllocationRule.Id, line: 27, character: 29); // Diagnostic: (27,29): warning HeapAnalyzerDelegateOnStructRule: Struct instance method being used for delegate creation, this will result in a boxing instruction AssertEx.ContainsDiagnostic(info.Allocations, id: AllocationRules.DelegateOnStructInstanceRule.Id, line: 27, character: 29); // Diagnostic: (27,29): warning HeapAnalyzerDelegateOnStructRule: Struct instance method being used for delegate creation, this will result in a boxing instruction AssertEx.ContainsDiagnostic(info.Allocations, id: AllocationRules.DelegateOnStructInstanceRule.Id, line: 28, character: 54); }
public void TypeConversionAllocation_InterpolatedStringWithInt_BoxingWarning() { var sampleProgram = @"string s = $""{1}"";"; var analyser = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyser, sampleProgram, ImmutableArray.Create(SyntaxKind.Interpolation)); Assert.AreEqual(1, info.Allocations.Count); AssertEx.ContainsDiagnostic(info.Allocations, id: TypeConversionAllocationAnalyzer.ValueTypeToReferenceTypeConversionRule.Id, line: 1, character: 15); }
public void TypeConversionAllocation_DoNotWarnForForwardingActionOnStruct() { const string snippet = @" using System; struct Foo { void Perform(Action process) { Forward(process); } void Forward(Action process) { process(); } }"; var analyzer = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyzer, snippet, ImmutableArray.Create(SyntaxKind.Argument)); Assert.AreEqual(0, info.Allocations.Count); }
public void TypeConversionAllocation_BinaryExpressionSyntax_WithDelegates() { var sampleProgram = @"using System; public class MyClass { public void Testing() { Func<object, string> temp = null; var result1 = temp ?? fooObjCall; // implicit, so Allocation var result2 = temp ?? new Func<object, string>(fooObjCall); // Explicit, so NO Allocation } private string fooObjCall(object obj) { return obj.ToString(); } } public struct MyStruct { public void Testing() { Func<object, string> temp = null; var result1 = temp ?? fooObjCall; // implicit, so Allocation var result2 = temp ?? new Func<object, string>(fooObjCall); // Explicit, so just warn for boxing } private string fooObjCall(object obj) { return obj.ToString(); } }"; var analyser = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyser, sampleProgram, ImmutableArray.Create(SyntaxKind.CoalesceExpression, SyntaxKind.AsExpression)); Assert.AreEqual(4, info.Allocations.Count); // Diagnostic: (8,31): warning HeapAnalyzerMethodGroupAllocationRule: This will allocate a delegate instance AssertEx.ContainsDiagnostic(info.Allocations, id: AllocationRules.MethodGroupAllocationRule.Id, line: 8, character: 31); // Diagnostic: (23,31): warning HeapAnalyzerMethodGroupAllocationRule: This will allocate a delegate instance AssertEx.ContainsDiagnostic(info.Allocations, id: AllocationRules.MethodGroupAllocationRule.Id, line: 23, character: 31); // Diagnostic: (23,31): warning HeapAnalyzerDelegateOnStructRule: Struct instance method being used for delegate creation, this will result in a boxing instruction AssertEx.ContainsDiagnostic(info.Allocations, id: AllocationRules.DelegateOnStructInstanceRule.Id, line: 23, character: 31); // Diagnostic: (23,31): warning HeapAnalyzerDelegateOnStructRule: Struct instance method being used for delegate creation, this will result in a boxing instruction AssertEx.ContainsDiagnostic(info.Allocations, id: AllocationRules.DelegateOnStructInstanceRule.Id, line: 24, character: 56); }
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); }
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); }
public void TypeConversionAllocation_EqualsValueClauseSyntax_WithDelegates() { var sampleProgram = @"using System; public class MyClass { public void Testing() { Func<object, string> func2 = fooObjCall; // implicit, so Allocation Func<object, string> func1 = new Func<object, string>(fooObjCall); // Explicit, so NO Allocation } private string fooObjCall(object obj) { return obj.ToString(); } } public struct MyStruct { public void Testing() { Func<object, string> func2 = fooObjCall; // implicit allocation + boxing Func<object, string> func1 = new Func<object, string>(fooObjCall); // Explicit allocation + boxing } private string fooObjCall(object obj) { return obj.ToString(); } }"; var analyser = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyser, sampleProgram, ImmutableArray.Create(SyntaxKind.CoalesceExpression, SyntaxKind.EqualsValueClause)); Assert.AreEqual(4, info.Allocations.Count); // Diagnostic: (7,38): warning HeapAnalyzerMethodGroupAllocationRule: This will allocate a delegate instance AssertEx.ContainsDiagnostic(info.Allocations, id: TypeConversionAllocationAnalyzer.MethodGroupAllocationRule.Id, line: 7, character: 38); // Diagnostic: (21,38): warning HeapAnalyzerMethodGroupAllocationRule: This will allocate a delegate instance AssertEx.ContainsDiagnostic(info.Allocations, id: TypeConversionAllocationAnalyzer.MethodGroupAllocationRule.Id, line: 21, character: 38); // Diagnostic: (21,38): warning HeapAnalyzerDelegateOnStructRule: Struct instance method being used for delegate creation, this will result in a boxing instruction AssertEx.ContainsDiagnostic(info.Allocations, id: TypeConversionAllocationAnalyzer.DelegateOnStructInstanceRule.Id, line: 21, character: 38); AssertEx.ContainsDiagnostic(info.Allocations, id: TypeConversionAllocationAnalyzer.DelegateOnStructInstanceRule.Id, line: 22, character: 63); // TODO this is a false positive // Diagnostic: (22,63): warning HeapAnalyzerDelegateOnStructRule: Struct instance method being used for delegate creation, this will result in a boxing instruction }
public void TypeConversionAllocation_CastExpressionSyntax() { var sampleProgram = @"using System; var f1 = (object)5; // Allocation var f2 = (object)""5""; // NO Allocation "; var analyser = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyser, sampleProgram, ImmutableArray.Create(SyntaxKind.CastExpression)); Assert.AreEqual(1, info.Allocations.Count); // Diagnostic: (3,18): warning HeapAnalyzerBoxingRule: Value type to reference type conversion causes boxing at call site (here), and unboxing at the callee-site. Consider using generics if applicable AssertEx.ContainsDiagnostic(info.Allocations, id: TypeConversionAllocationAnalyzer.ValueTypeToReferenceTypeConversionRule.Id, line: 3, character: 18); }
public void TypeConversionAllocation_DelegateAssignmentToReadonly_DoNotWarn() { string[] snippets = { @"private readonly System.Func<string, bool> fileExists = System.IO.File.Exists;", @"private static readonly System.Func<string, bool> fileExists = System.IO.File.Exists;", @"private System.Func<string, bool> fileExists { get; } = System.IO.File.Exists;", @"private static System.Func<string, bool> fileExists { get; } = System.IO.File.Exists;" }; var analyzer = new TypeConversionAllocationAnalyzer(); foreach (var snippet in snippets) { var info = ProcessCode(analyzer, snippet, ImmutableArray.Create(SyntaxKind.Argument)); Assert.AreEqual(1, info.Allocations.Count(x => x.Id == TypeConversionAllocationAnalyzer.ReadonlyMethodGroupAllocationRule.Id), snippet); } }
public void TypeConversionAllocation_ConditionalExpressionSyntax() { var sampleProgram = @"using System; object obj = ""test""; object test1 = true ? 0 : obj; // Allocation object test2 = true ? 0.ToString() : obj; // NO Allocation "; var analyser = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyser, sampleProgram, ImmutableArray.Create(SyntaxKind.ConditionalExpression)); Assert.AreEqual(1, info.Allocations.Count); // Diagnostic: (4,23): warning HeapAnalyzerBoxingRule: Value type to reference type conversion causes boxing at call site (here), and unboxing at the callee-site. Consider using generics if applicable AssertEx.ContainsDiagnostic(info.Allocations, id: TypeConversionAllocationAnalyzer.ValueTypeToReferenceTypeConversionRule.Id, line: 4, character: 23); }
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); }
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); }
public void TypeConversionAllocation_ArgumentWithImplicitStringCastOperator() { const string programWithoutImplicitCastOperator = @" public struct AStruct { public static void Dump(AStruct astruct) { System.Console.WriteLine(astruct); } } "; const string programWithImplicitCastOperator = @" public struct AStruct { public readonly string WrappedString; public AStruct(string s) { WrappedString = s ?? """"; } public static void Dump(AStruct astruct) { System.Console.WriteLine(astruct); } public static implicit operator string(AStruct astruct) { return astruct.WrappedString; } } "; var analyzer = new TypeConversionAllocationAnalyzer(); var info0 = ProcessCode(analyzer, programWithoutImplicitCastOperator, ImmutableArray.Create(SyntaxKind.Argument)); AssertEx.ContainsDiagnostic(info0.Allocations, id: TypeConversionAllocationAnalyzer.ValueTypeToReferenceTypeConversionRule.Id, line: 6, character: 50); var info1 = ProcessCode(analyzer, programWithImplicitCastOperator, ImmutableArray.Create(SyntaxKind.Argument)); Assert.AreEqual(0, info1.Allocations.Count); }
public void Converting_any_enumeration_type_to_System_Enum_type() { var @script = @"enum E { A } System.Enum box = E.A;"; var analyser = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyser, @script, ImmutableArray.Create( SyntaxKind.SimpleAssignmentExpression, SyntaxKind.ReturnStatement, SyntaxKind.YieldReturnStatement, SyntaxKind.CastExpression, SyntaxKind.AsExpression, SyntaxKind.CoalesceExpression, SyntaxKind.ConditionalExpression, SyntaxKind.ForEachStatement, SyntaxKind.EqualsValueClause, SyntaxKind.Argument)); Assert.Single(info.Allocations); // Diagnostic: (2,35): warning HeapAnalyzerBoxingRule: Value type to reference type conversion causes boxing at call site (here), and unboxing at the callee-site. Consider using generics if applicable AssertEx.ContainsDiagnostic(info.Allocations, TypeConversionAllocationAnalyzer.ValueTypeToReferenceTypeConversionRule.Id, line: 2, character: 35); }
// TODO: [Fact] public void TypeConversionAllocation_ImplicitStringCastOperator() { var sampleProgram = @" public struct AStruct { public readonly string WrappedString; public AStruct(string s) { WrappedString = s ?? """"; } public static void Dump(AStruct astruct) { System.Console.WriteLine(astruct); } public static implicit operator string(AStruct astruct) { return astruct.WrappedString; } } public class Program { public static void Main() { var astruct = new AStruct(System.Environment.MachineName); AStruct.Dump(astruct); } } "; var analyzer = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyzer, sampleProgram, ImmutableArray.Create(SyntaxKind.Argument)); Assert.Empty(info.Allocations); // currently info.Allocations.Count == 1 // with info.Allocations[0] = // (13,50): warning HeapAnalyzerBoxingRule: Value type to reference type conversion causes boxing at call site (here), and unboxing at the callee-site. Consider using generics if applicable }
public void TypeConversionAllocation_ReturnStatementSyntax() { var sampleProgram = @"using System; var result1 = new MyObject().Obj; // Allocation var result2 = new MyObject().ObjNoAllocation; // Allocation public class MyObject { public Object Obj { get { return 0; } } public Object ObjNoAllocation { get { return 0.ToString(); } } }"; var analyser = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyser, sampleProgram, ImmutableArray.Create(SyntaxKind.ReturnStatement)); Assert.AreEqual(1, info.Allocations.Count); // Diagnostic: (7,38): warning HeapAnalyzerBoxingRule: Value type to reference type conversion causes boxing at call site (here), and unboxing at the callee-site. Consider using generics if applicable AssertEx.ContainsDiagnostic(info.Allocations, id: TypeConversionAllocationAnalyzer.ValueTypeToReferenceTypeConversionRule.Id, line: 8, character: 38); }
public void TypeConversionAllocation_NoDiagnosticWhenPassingDelegateAsArgument() { const string snippet = @" using System; struct Foo { void Do(Action process) { DoMore(process); // Analyzer triggers warning here, indicating 'process' will be boxed. } void DoMore(Action process) { process(); } } "; var analyzer = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyzer, snippet, ImmutableArray.Create(SyntaxKind.Argument)); AssertEx.ContainsNoDiagnostic(info.Allocations, TypeConversionAllocationAnalyzer.DelegateOnStructInstanceRule.Id, 7, 16); }
public void TypeConversionAllocation_BinaryExpressionSyntax() { var sampleProgram = @"using System; object x = ""blah""; object a1 = x ?? 0; // Allocation object a2 = x ?? 0.ToString(); // No Allocation var b1 = 10 as object; // Allocation var b2 = 10.ToString() as object; // No Allocation "; var analyser = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyser, sampleProgram, ImmutableArray.Create(SyntaxKind.CoalesceExpression, SyntaxKind.AsExpression)); Assert.AreEqual(2, info.Allocations.Count); // Diagnostic: (4,17): warning HeapAnalyzerBoxingRule: Value type to reference type conversion causes boxing at call site (here), and unboxing at the callee-site. Consider using generics if applicable AssertEx.ContainsDiagnostic(info.Allocations, id: TypeConversionAllocationAnalyzer.ValueTypeToReferenceTypeConversionRule.Id, line: 4, character: 18); // Diagnostic: (7,9): warning HeapAnalyzerBoxingRule: Value type to reference type conversion causes boxing at call site (here), and unboxing at the callee-site. Consider using generics if applicable AssertEx.ContainsDiagnostic(info.Allocations, id: TypeConversionAllocationAnalyzer.ValueTypeToReferenceTypeConversionRule.Id, line: 7, character: 10); }
public void TypeConversionAllocation_YieldReturnImplicitStringCastOperator() { const string programWithoutImplicitCastOperator = @" public struct AStruct { public System.Collections.Generic.IEnumerator<object> GetEnumerator() { yield return this; } } "; const string programWithImplicitCastOperator = @" public struct AStruct { public System.Collections.Generic.IEnumerator<string> GetEnumerator() { yield return this; } public static implicit operator string(AStruct astruct) { return """"; } } "; var analyzer = new TypeConversionAllocationAnalyzer(); var info0 = ProcessCode(analyzer, programWithoutImplicitCastOperator, ImmutableArray.Create(SyntaxKind.Argument)); AssertEx.ContainsDiagnostic(info0.Allocations, id: TypeConversionAllocationAnalyzer.ValueTypeToReferenceTypeConversionRule.Id, line: 6, character: 38); var info1 = ProcessCode(analyzer, programWithImplicitCastOperator, ImmutableArray.Create(SyntaxKind.Argument)); Assert.AreEqual(0, info1.Allocations.Count); }
public void TypeConversionAllocation_WarnForExplicitDelegateOnStruct() { const string snippet = @" using System; public struct MyStruct { public void Testing() { var @struct = new MyStruct(); @struct.ProcessFunc(new Func<object, string>(FooObjCall)); } public void ProcessFunc(Func<object, string> func) { } private string FooObjCall(object obj) { return obj.ToString(); } }"; var analyzer = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyzer, snippet, ImmutableArray.Create( SyntaxKind.Argument)); Assert.AreEqual(1, info.Allocations.Count); AssertEx.ContainsDiagnostic(info.Allocations, id: AllocationRules.DelegateOnStructInstanceRule.Id, line: 6, character: 66); }
public void TypeConversionAllocation_DoNotReportBoxingAllocationForPassingStructStaticMethodForDelegateConstructor() { const string snippet = @" using System; public struct MyStruct { public void Testing() { var @struct = new MyStruct(); @struct.ProcessFunc(new Func<object, string>(FooObjCall)); } public void ProcessFunc(Func<object, string> func) { } private static string FooObjCall(object obj) { return obj.ToString(); } } "; var analyzer = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyzer, snippet, ImmutableArray.Create(SyntaxKind.Argument)); AssertEx.ContainsNoDiagnostic(info.Allocations, TypeConversionAllocationAnalyzer.DelegateOnStructInstanceRule.Id, 6, 54); }
public void TypeConversionAllocation_YieldStatementSyntax() { var sampleProgram = @"using System; using System.Collections.Generic; foreach (var item in GetItems()) { } foreach (var item in GetItemsNoAllocation()) { } public IEnumerable<object> GetItems() { yield return 0; // Allocation yield break; } public IEnumerable<int> GetItemsNoAllocation() { yield return 0; // NO Allocation (IEnumerable<int>) yield break; }"; var analyser = new TypeConversionAllocationAnalyzer(); var info = ProcessCode(analyser, sampleProgram, ImmutableArray.Create(SyntaxKind.YieldReturnStatement)); Assert.AreEqual(1, info.Allocations.Count); // Diagnostic: (14,18): warning HeapAnalyzerBoxingRule: Value type to reference type conversion causes boxing at call site (here), and unboxing at the callee-site. Consider using generics if applicable AssertEx.ContainsDiagnostic(info.Allocations, id: TypeConversionAllocationAnalyzer.ValueTypeToReferenceTypeConversionRule.Id, line: 14, character: 18); // TODO this is a false positive // Diagnostic: (8,22): warning HeapAnalyzerBoxingRule: Value type to reference type conversion causes boxing at call site (here), and unboxing at the callee-site. Consider using generics if applicable }