1
ļ»æ// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
3
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4
// software and associated documentation files (the "Software"), to deal in the Software
5
// without restriction, including without limitation the rights to use, copy, modify, merge,
6
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7
// to whom the Software is furnished to do so, subject to the following conditions:
9
// The above copyright notice and this permission notice shall be included in all copies or
10
// substantial portions of the Software.
12
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17
// DEALINGS IN THE SOFTWARE.
23
using ICSharpCode.NRefactory.CSharp.TypeSystem;
24
using ICSharpCode.NRefactory.Semantics;
25
using ICSharpCode.NRefactory.TypeSystem;
26
using ICSharpCode.NRefactory.TypeSystem.Implementation;
27
using NUnit.Framework;
29
namespace ICSharpCode.NRefactory.CSharp.Resolver
32
public class LambdaTests : ResolverTestBase
35
public void SimpleLambdaTest()
37
string program = @"using System;
40
Test(i => Console.WriteLine(i));
42
public void Test(Action<int> ac) { ac(42); }
44
var lrr = Resolve<LocalResolveResult>(program.Replace("(i)", "($i$)"));
45
Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
47
lrr = Resolve<LocalResolveResult>(program.Replace("i =>", "$i$ =>"));
48
Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
52
public void LambdaInConstructorTest()
54
string program = @"using System;
57
TestClass t = new TestClass(i => Console.WriteLine($i$));
59
public TestClass(Action<int> ac) { ac(42); }
61
var lrr = Resolve<LocalResolveResult>(program);
62
Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
66
public void LambdaInGenericConstructorTest()
68
string program = @"using System;
71
var t = new SomeClass<string>(i => Console.WriteLine($i$));
75
public SomeClass(Action<T> ac) { }
77
var lrr = Resolve<LocalResolveResult>(program);
78
Assert.AreEqual("System.String", lrr.Type.ReflectionName);
81
#region Lambda In Array Initializer
83
public void LambdaInArrayInitializer1()
85
string program = @"using System;
88
Converter<int, string>[] arr = {
93
var lrr = Resolve<LocalResolveResult>(program);
94
Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
98
public void LambdaInArrayInitializer2()
100
string program = @"using System;
103
a = new Converter<int, string>[] {
108
var lrr = Resolve<LocalResolveResult>(program);
109
Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
113
public void LambdaInArrayInitializer3()
115
string program = @"using System;
117
Converter<int, string>[] field = new Converter<int, string>[] {
121
var lrr = Resolve<LocalResolveResult>(program);
122
Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
126
public void LambdaInArrayInitializer4()
128
string program = @"using System;
130
Converter<int, string>[] field = {
134
var lrr = Resolve<LocalResolveResult>(program);
135
Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
139
public void LambdaIn2DArrayInitializer()
141
string program = @"using System;
144
Converter<int, string>[,] arr = {
145
{ i => $i$.ToString() }
149
var lrr = Resolve<LocalResolveResult>(program);
150
Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
154
public void LambdaInInferred2DArrayInitializer()
156
string program = @"using System;
159
var c = new [,] { { null, (Converter<int, string>)null }, { a => $a$.ToString(), b => b.ToString() }};
162
var lrr = Resolve<LocalResolveResult>(program);
163
Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
167
#region Lambda In Collection Initializer
169
public void LambdaInCollectionInitializer1()
171
string program = @"using System; using System.Collections.Generic;
174
a = new List<Converter<int, string>> {
179
var lrr = Resolve<LocalResolveResult>(program);
180
Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
184
public void LambdaInCollectionInitializer2()
186
string program = @"using System; using System.Collections.Generic;
189
a = new Dictionary<Func<char, string>, Converter<int, string>> {
190
{ i => $i$.ToString(), i => i.ToString() }
194
var lrr = Resolve<LocalResolveResult>(program);
195
Assert.AreEqual("System.Char", lrr.Type.ReflectionName);
199
public void LambdaInCollectionInitializer3()
201
string program = @"using System; using System.Collections.Generic;
204
a = new Dictionary<Func<char, string>, Converter<int, string>> {
205
{ i => i.ToString(), $i$ => i.ToString() }
209
var lrr = Resolve<LocalResolveResult>(program);
210
Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
215
public void LambdaInObjectInitializerTest()
217
string program = @"using System;
220
Helper h = new Helper {
221
F = i => $i$.ToString()
226
public Converter<int, string> F;
228
var lrr = Resolve<LocalResolveResult>(program);
229
Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
233
public void LambdaExpressionInCastExpression()
235
string program = @"using System;
236
static class TestClass {
237
static void Main(string[] args) {
238
var f = (Func<int, string>) ( i => $i$ );
240
public delegate R Func<T, R>(T arg);
242
var lrr = Resolve<LocalResolveResult>(program);
243
Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
247
public void LambdaExpressionInDelegateCreateExpression()
249
string program = @"using System;
250
static class TestClass {
251
static void Main(string[] args) {
252
var f = new Func<int, string>( i => $i$ );
254
public delegate R Func<T, R>(T arg);
256
var lrr = Resolve<LocalResolveResult>(program);
257
Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
261
public void LambdaExpressionInReturnStatement()
263
string program = @"using System;
264
static class TestClass {
265
static Converter<int, string> GetToString() {
266
return i => $i$.ToString();
269
var lrr = Resolve<LocalResolveResult>(program);
270
Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
274
public void LambdaExpressionInReturnStatementInStatementLambda()
276
string program = @"using System;
277
static class TestClass {
278
static void SomeMethod() {
279
Func<Func<string, string>> getStringTransformer = () => {
280
return s => $s$.ToUpper();
283
public delegate R Func<T, R>(T arg);
284
public delegate R Func<R>();
286
var lrr = Resolve<LocalResolveResult>(program);
287
Assert.AreEqual("System.String", lrr.Type.ReflectionName);
291
public void LambdaExpressionInReturnStatementInAnonymousMethod()
293
string program = @"using System;
294
static class TestClass {
295
static void SomeMethod() {
296
Func<Func<string, string>> getStringTransformer = delegate {
297
return s => $s$.ToUpper();
300
public delegate R Func<T, R>(T arg);
301
public delegate R Func<R>();
303
var lrr = Resolve<LocalResolveResult>(program);
304
Assert.AreEqual("System.String", lrr.Type.ReflectionName);
308
public void CurriedLambdaExpressionInCastExpression()
310
string program = @"using System;
311
static class TestClass {
312
static void Main(string[] args) {
313
var f = (Func<char, Func<string, int>>) ( a => b => 0 );
315
public delegate R Func<T, R>(T arg);
317
var lrr = Resolve<LocalResolveResult>(program.Replace("a =>", "$a$ =>"));
318
Assert.AreEqual("System.Char", lrr.Type.ReflectionName);
320
lrr = Resolve<LocalResolveResult>(program.Replace("b =>", "$b$ =>"));
321
Assert.AreEqual("System.String", lrr.Type.ReflectionName);
325
public void LambdaExpressionInVariableInitializer()
327
string program = @"using System;
328
static class TestClass {
330
Func<int, string> f = $i$ => i.ToString();
332
public delegate R Func<T, R>(T arg);
334
var lrr = Resolve<LocalResolveResult>(program);
335
Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
339
public void LambdaExpressionInVariableAssignment()
341
string program = @"using System;
342
static class TestClass {
345
f = $i$ => i.ToString();
347
public delegate R Func<T, R>(T arg);
349
var lrr = Resolve<LocalResolveResult>(program);
350
Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
354
public void LambdaInDelegateCall()
356
string program = @"using System;
359
Func<Func<int, string>, char> f;
360
f($i$ => i.ToString());
362
public delegate R Func<T, R>(T arg);
364
var lrr = Resolve<LocalResolveResult>(program);
365
Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
369
public void ConvertAllInGenericMethod()
371
string program = @"using System;
373
static void Method<T>(System.Collections.Generic.List<T> list) {
374
$list.ConvertAll(x => (int)(object)x)$;
377
var rr = Resolve<CSharpInvocationResolveResult>(program);
378
Assert.IsFalse(rr.IsError);
379
var m = (IMethod)rr.Member;
380
Assert.AreEqual("System.Int32", m.TypeArguments[0].ReflectionName);
381
Assert.AreEqual("System.Converter`2[[``0],[System.Int32]]", m.Parameters[0].Type.ReflectionName);
383
var crr = (ConversionResolveResult)rr.Arguments[0];
384
Assert.IsTrue(crr.Conversion.IsAnonymousFunctionConversion);
385
Assert.AreEqual("System.Converter`2[[``0],[System.Int32]]", crr.Type.ReflectionName);
389
public void AnonymousMethodWithoutParameterList()
391
string program = @"using System;
393
event EventHandler Ev = $delegate {}$;
395
var rr = Resolve<LambdaResolveResult>(program);
396
Assert.IsFalse(rr.IsError);
397
Assert.IsFalse(rr.HasParameterList);
401
public void NonVoidMethodInActionLambdaIsValidConversion()
403
string program = @"using System;
405
void Run(Action a) { }
410
var c = GetConversion(program);
411
Assert.IsTrue(c.IsValid);
415
public void NonVoidMethodInImplicitlyTypedActionLambdaIsValidConversion()
417
string program = @"using System;
419
void Run(Action<string> a) { }
424
var c = GetConversion(program);
425
Assert.IsTrue(c.IsValid);
429
public void ImplicitLambdaInNewFunc()
431
string program = @"using System;
434
object x = new Func<int, string>(a => $a$.ToString());
436
var r = Resolve(program);
437
Assert.AreEqual("System.Int32", r.Type.ReflectionName);
441
public void LambdaInNewAction()
443
string program = @"using System;
446
object x = new Action(() => $b = true$);
448
var c = GetConversion(program);
449
Assert.IsTrue(c.IsValid);
453
public void AnonymousMethodInNewEventHandler()
455
// The switch statement causes the control flow analysis to ask the resolver if it's a constant,
456
// which caused a bug.
457
string program = @"using System;
460
object x = new EventHandler<AssemblyLoadEventArgs>($delegate (object sender, AssemblyLoadEventArgs e) { switch (e.Action) {} }$);
462
var c = GetConversion(program);
463
Assert.IsTrue(c.IsValid);
467
public void ThrowingAnonymousMethodIsConvertibleToFunc()
469
string program = @"using System;
471
Func<string, int> x = $delegate { throw new NotImplementedException(); }$;
473
var c = GetConversion(program);
474
Assert.IsTrue(c.IsValid);
478
public void EmptyAnonymousMethodIsNotConvertibleToFunc()
480
string program = @"using System;
482
Func<string, int> x = $delegate { }$;
484
var c = GetConversion(program);
485
Assert.IsFalse(c.IsValid);
489
public void RaisePropertyChanged_WithExpressionLambda()
491
string program = @"using System;
492
using System.Linq.Expressions;
494
void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression) {}
495
void RaisePropertyChanged(string propertyName) {}
496
string MyProperty { get {} }
498
$RaisePropertyChanged(() => MyProperty)$;
501
var rr = Resolve<CSharpInvocationResolveResult>(program);
502
Assert.IsFalse(rr.IsError);
503
Assert.AreEqual("propertyExpression", rr.Member.Parameters.Single().Name);
507
public void ParenthesizedExpressionIsNotValidExpressionStatement()
509
string program = @"using System;
511
static void Foo(string x, Action<Action> y) { Console.WriteLine(1); }
512
static void Foo(object x, Func<Func<int>, int> y) { Console.WriteLine(2); }
516
var rr = ResolveAtLocation<CSharpInvocationResolveResult>(program + "$Foo(null, x => x()); // Prints 1\n}}");
517
Assert.IsFalse(rr.IsError);
518
Assert.AreEqual("System.String", rr.Member.Parameters[0].Type.ReflectionName);
520
rr = ResolveAtLocation<CSharpInvocationResolveResult>(program + "$Foo(null, x => (x())); // Prints 2\n}}");
521
Assert.IsFalse(rr.IsError);
522
Assert.AreEqual("System.Object", rr.Member.Parameters[0].Type.ReflectionName);
526
public void LambdaWithComparisonToString()
528
string program = @"using System;
530
static void Foo(Func<int, bool> f) {}
531
static void Foo(Func<string, bool> f) {}
532
static void Main() { $Foo(x => x == ""text"")$; } }";
533
var rr = Resolve<CSharpInvocationResolveResult>(program);
534
Assert.IsFalse(rr.IsError);
535
var invoke = rr.Member.Parameters.Single().Type.GetDelegateInvokeMethod();
536
Assert.AreEqual("System.String", invoke.Parameters.Single().Type.ReflectionName);
540
public void LambdaWithComparisonToInt()
542
string program = @"using System;
544
static void Foo(Func<int, bool> f) {}
545
static void Foo(Func<string, bool> f) {}
546
static void Main() { $Foo(x => x == 42)$; } }";
547
var rr = Resolve<CSharpInvocationResolveResult>(program);
548
Assert.IsFalse(rr.IsError);
549
var invoke = rr.Member.Parameters.Single().Type.GetDelegateInvokeMethod();
550
Assert.AreEqual("System.Int32", invoke.Parameters.Single().Type.ReflectionName);
554
public void StartNewTask()
556
string program = @"using System;
560
$System.Threading.Tasks.Task.Factory.StartNew(() => Calculate())$;
562
var rr = Resolve<CSharpInvocationResolveResult>(program);
563
Assert.IsFalse(rr.IsError);
564
Assert.AreEqual("System.Threading.Tasks.Task`1[[System.Int32]]", rr.Type.ReflectionName);
568
public void LambdaParameterIdentity()
570
string code = @"using System;
573
Func<int, int> f = $i => i + 1$;
577
var prep = PrepareResolver(code);
578
var lambda = (LambdaExpression)prep.Item2;
579
var identifierInLambdaBody = ((BinaryOperatorExpression)lambda.Body).Left;
580
var resolver = prep.Item1;
582
var resolvedParameter = ((LocalResolveResult)resolver.Resolve(lambda.Parameters.Single())).Variable;
583
var parameterInResolveResult = ((LambdaResolveResult)resolver.Resolve(lambda)).Parameters[0];
584
var referencedParameter = ((LocalResolveResult)resolver.Resolve(identifierInLambdaBody)).Variable;
586
Assert.AreEqual("System.Int32" ,resolvedParameter.Type.ReflectionName);
587
Assert.AreSame(resolvedParameter, parameterInResolveResult);
588
Assert.AreSame(resolvedParameter, referencedParameter);
592
public void MultipleOverloadsWithImplicitLambda()
594
string program = @"class MainClass {
598
delegate R Func<T, R>(T arg);
599
int M(Func<int, int> f){ }
600
string M(Func<string, string> f){ }
602
var mrr = Resolve<CSharpInvocationResolveResult>(program);
603
Assert.IsFalse(mrr.IsError);
604
Assert.AreEqual("System.String", mrr.Type.ReflectionName);
608
public void MultipleOverloadsWithImplicitLambda2()
610
string program = @"class MainClass {
614
delegate R Func<T, R>(T arg);
615
int M(Func<int, int> f){ }
616
string M(Func<string, int> f){ }
618
var mrr = Resolve<CSharpInvocationResolveResult>(program);
619
Assert.IsFalse(mrr.IsError);
620
Assert.AreEqual("System.String", mrr.Type.ReflectionName);
624
public void MultipleOverloadsWithImplicitLambda3()
626
string program = @"class MainClass {
630
delegate R Func<T, R>(T arg);
631
string M(Func<string, int> f){ }
632
int M(Func<int, int> f){ }
634
var mrr = Resolve<CSharpInvocationResolveResult>(program);
635
Assert.IsFalse(mrr.IsError);
636
Assert.AreEqual("System.Int32", mrr.Type.ReflectionName);
640
public void AsyncLambdaWithAwait()
644
using System.Threading.Tasks;
648
public Task OpenAsync ()
658
await $Test (async () => { await new A().OpenAsync (); })$;
661
T Test<T> (Func<T> func)
667
var mrr = Resolve<CSharpInvocationResolveResult>(program);
668
Assert.IsFalse(mrr.IsError);
669
Assert.AreEqual("System.Threading.Tasks.Task", mrr.Type.ReflectionName);
673
public void ConversionInExplicitlyTypedLambdaBody() {
674
string program = @"using System;
677
System.Func<int, string> f = $(int i) => null$;
680
var rr = Resolve<LambdaResolveResult>(program);
681
Assert.IsInstanceOf<ConversionResolveResult>(rr.Body);
682
Assert.That(((ConversionResolveResult)rr.Body).Conversion.IsNullLiteralConversion);
686
public void ConversionInImplicitlyTypedLambdaBody() {
687
string program = @"using System;
690
System.Func<int, string> f = $i => null$;
693
var rr = Resolve<LambdaResolveResult>(program);
694
Assert.IsInstanceOf<ConversionResolveResult>(rr.Body);
695
Assert.That(((ConversionResolveResult)rr.Body).Conversion.IsNullLiteralConversion);
699
public void NoConversionInVoidExplicitlyTypedLambdaBody() {
700
string program = @"using System;
703
System.Action<int> f = $(int i) => i++$;
706
var rr = Resolve<LambdaResolveResult>(program);
707
Assert.IsInstanceOf<OperatorResolveResult>(rr.Body);
711
public void NoConversionInVoidImplicitlyTypedLambdaBody() {
712
string program = @"using System;
715
System.Action<int> f = $i => i++$;
718
var rr = Resolve<LambdaResolveResult>(program);
719
Assert.IsInstanceOf<OperatorResolveResult>(rr.Body);
723
public void NumericConversion()
725
string program = @"using System;
728
Func<int, double> f = $i => i + 1$;
731
var rr = Resolve<LambdaResolveResult>(program);
732
Assert.IsInstanceOf<ConversionResolveResult>(rr.Body);
733
var bodyConv = ((ConversionResolveResult)rr.Body).Conversion;
734
Assert.IsTrue(bodyConv.IsValid);
735
Assert.IsTrue(bodyConv.IsNumericConversion);
737
var c = GetConversion(program);
738
Assert.IsTrue(c.IsValid);
739
Assert.IsTrue(c.IsAnonymousFunctionConversion);
743
public void InvalidNumericConversion()
745
string program = @"using System;
748
Func<double, int> f = $i => i + 1$;
751
var rr = Resolve<LambdaResolveResult>(program);
752
Assert.IsInstanceOf<ConversionResolveResult>(rr.Body);
753
var bodyConv = ((ConversionResolveResult)rr.Body).Conversion;
754
Assert.IsFalse(bodyConv.IsValid);
756
var c = GetConversion(program);
757
Assert.IsFalse(c.IsValid);
758
Assert.IsTrue(c.IsAnonymousFunctionConversion);
762
public void ImplicitAsyncLambda()
764
string program = @"using System;
765
using System.Threading.Tasks;
768
Func<int, Task<int>> f = $async i => i + 1$;
771
var rr = Resolve<LambdaResolveResult>(program);
772
Assert.IsInstanceOf<OperatorResolveResult>(rr.Body);
773
Assert.AreEqual("System.Int32", rr.Body.Type.FullName);
775
var c = GetConversion(program);
776
Assert.IsTrue(c.IsValid);
777
Assert.IsTrue(c.IsAnonymousFunctionConversion);
781
public void ImplicitAsyncLambdaWithNumericConversion()
783
string program = @"using System;
784
using System.Threading.Tasks;
787
Func<int, Task<double>> f = $async i => i + 1$;
790
var rr = Resolve<LambdaResolveResult>(program);
791
Assert.IsInstanceOf<ConversionResolveResult>(rr.Body);
792
Assert.AreEqual("System.Double", rr.Body.Type.FullName);
794
var c = GetConversion(program);
795
Assert.IsTrue(c.IsValid);
796
Assert.IsTrue(c.IsAnonymousFunctionConversion);
800
public void ExplicitAsyncLambda()
802
string program = @"using System;
803
using System.Threading.Tasks;
806
Func<int, Task<int>> f = $async (int i) => i + 1$;
809
var rr = Resolve<LambdaResolveResult>(program);
810
Assert.IsInstanceOf<OperatorResolveResult>(rr.Body);
811
Assert.AreEqual("System.Int32", rr.Body.Type.FullName);
813
var c = GetConversion(program);
814
Assert.IsTrue(c.IsValid);
815
Assert.IsTrue(c.IsAnonymousFunctionConversion);
819
public void ExplicitAsyncLambdaWithNumericConversion()
821
string program = @"using System;
822
using System.Threading.Tasks;
825
Func<int, Task<double>> f = $async (int i) => i + 1$;
828
var rr = Resolve<LambdaResolveResult>(program);
829
Assert.IsInstanceOf<ConversionResolveResult>(rr.Body);
830
Assert.AreEqual("System.Double", rr.Body.Type.FullName);
832
var c = GetConversion(program);
833
Assert.IsTrue(c.IsValid);
834
Assert.IsTrue(c.IsAnonymousFunctionConversion);