~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/nrefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/OverloadResolutionTests.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
ļ»æ// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
 
2
// 
 
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:
 
8
// 
 
9
// The above copyright notice and this permission notice shall be included in all copies or
 
10
// substantial portions of the Software.
 
11
// 
 
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.
 
18
 
 
19
using System;
 
20
using System.Collections.Generic;
 
21
using System.Linq;
 
22
using System.Linq.Expressions;
 
23
 
 
24
using ICSharpCode.NRefactory.Semantics;
 
25
using ICSharpCode.NRefactory.TypeSystem;
 
26
using ICSharpCode.NRefactory.TypeSystem.Implementation;
 
27
using NUnit.Framework;
 
28
 
 
29
namespace ICSharpCode.NRefactory.CSharp.Resolver
 
30
{
 
31
        [TestFixture]
 
32
        public class OverloadResolutionTests
 
33
        {
 
34
                readonly ICompilation compilation = new SimpleCompilation(
 
35
                        CecilLoaderTests.SystemCore, new[] { CecilLoaderTests.Mscorlib });
 
36
                
 
37
                ResolveResult[] MakeArgumentList(params Type[] argumentTypes)
 
38
                {
 
39
                        return argumentTypes.Select(t => new ResolveResult(compilation.FindType(t))).ToArray();
 
40
                }
 
41
                
 
42
                IMethod MakeMethod(params object[] parameterTypesOrDefaultValues)
 
43
                {
 
44
                        var context = new SimpleTypeResolveContext(compilation.MainAssembly);
 
45
                        return (IMethod)MakeUnresolvedMethod(parameterTypesOrDefaultValues).CreateResolved(context);
 
46
                }
 
47
                
 
48
                DefaultUnresolvedMethod MakeUnresolvedMethod(params object[] parameterTypesOrDefaultValues)
 
49
                {
 
50
                        var m = new DefaultUnresolvedMethod();
 
51
                        m.Name = "Method";
 
52
                        foreach (var typeOrDefaultValue in parameterTypesOrDefaultValues) {
 
53
                                Type type = typeOrDefaultValue as Type;
 
54
                                if (type != null)
 
55
                                        m.Parameters.Add(new DefaultUnresolvedParameter(type.ToTypeReference(), string.Empty));
 
56
                                else if (Type.GetTypeCode(typeOrDefaultValue.GetType()) > TypeCode.Object)
 
57
                                        m.Parameters.Add(new DefaultUnresolvedParameter(typeOrDefaultValue.GetType().ToTypeReference(), string.Empty) {
 
58
                                                                DefaultValue = new SimpleConstantValue(typeOrDefaultValue.GetType().ToTypeReference(), typeOrDefaultValue)
 
59
                                                         });
 
60
                                else
 
61
                                        throw new ArgumentException(typeOrDefaultValue.ToString());
 
62
                        }
 
63
                        return m;
 
64
                }
 
65
                
 
66
                IMethod MakeParamsMethod(params object[] parameterTypesOrDefaultValues)
 
67
                {
 
68
                        var m = MakeUnresolvedMethod(parameterTypesOrDefaultValues);
 
69
                        ((DefaultUnresolvedParameter)m.Parameters.Last()).IsParams = true;
 
70
                        var context = new SimpleTypeResolveContext(compilation.MainAssembly);
 
71
                        return (IMethod)m.CreateResolved(context);
 
72
                }
 
73
                
 
74
                IUnresolvedParameter MakeOptionalParameter(ITypeReference type, string name)
 
75
                {
 
76
                        return new DefaultUnresolvedParameter(type, name) {
 
77
                                DefaultValue = new SimpleConstantValue(type, null)
 
78
                        };
 
79
                }
 
80
                
 
81
                [Test]
 
82
                public void PreferIntOverUInt()
 
83
                {
 
84
                        OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList(typeof(ushort)));
 
85
                        var c1 = MakeMethod(typeof(int));
 
86
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(c1));
 
87
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeMethod(typeof(uint))));
 
88
                        Assert.IsFalse(r.IsAmbiguous);
 
89
                        Assert.AreSame(c1, r.BestCandidate);
 
90
                }
 
91
                
 
92
                [Test]
 
93
                public void PreferUIntOverLong_FromIntLiteral()
 
94
                {
 
95
                        ResolveResult[] args = { new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), 1) };
 
96
                        OverloadResolution r = new OverloadResolution(compilation, args);
 
97
                        var c1 = MakeMethod(typeof(uint));
 
98
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(c1));
 
99
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeMethod(typeof(long))));
 
100
                        Assert.IsFalse(r.IsAmbiguous);
 
101
                        Assert.AreSame(c1, r.BestCandidate);
 
102
                }
 
103
                
 
104
                [Test]
 
105
                public void NullableIntAndNullableUIntIsAmbiguous()
 
106
                {
 
107
                        OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList(typeof(ushort?)));
 
108
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeMethod(typeof(int?))));
 
109
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeMethod(typeof(uint?))));
 
110
                        Assert.AreEqual(OverloadResolutionErrors.AmbiguousMatch, r.BestCandidateErrors);
 
111
                        
 
112
                        // then adding a matching overload solves the ambiguity:
 
113
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeMethod(typeof(ushort?))));
 
114
                        Assert.AreEqual(OverloadResolutionErrors.None, r.BestCandidateErrors);
 
115
                        Assert.IsNull(r.BestCandidateAmbiguousWith);
 
116
                }
 
117
                
 
118
                [Test]
 
119
                public void ParamsMethodMatchesEmptyArgumentList()
 
120
                {
 
121
                        OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList());
 
122
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeParamsMethod(typeof(int[]))));
 
123
                        Assert.IsTrue(r.BestCandidateIsExpandedForm);
 
124
                }
 
125
                
 
126
                [Test]
 
127
                public void ParamsMethodMatchesOneArgumentInExpandedForm()
 
128
                {
 
129
                        OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList(typeof(int)));
 
130
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeParamsMethod(typeof(int[]))));
 
131
                        Assert.IsTrue(r.BestCandidateIsExpandedForm);
 
132
                }
 
133
                
 
134
                [Test]
 
135
                public void ParamsMethodMatchesInUnexpandedForm()
 
136
                {
 
137
                        OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList(typeof(int[])));
 
138
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeParamsMethod(typeof(int[]))));
 
139
                        Assert.IsFalse(r.BestCandidateIsExpandedForm);
 
140
                }
 
141
                
 
142
                [Test]
 
143
                public void LessArgumentsPassedToParamsIsBetter()
 
144
                {
 
145
                        OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList(typeof(int), typeof(int), typeof(int)));
 
146
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeParamsMethod(typeof(int[]))));
 
147
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(MakeParamsMethod(typeof(int), typeof(int[]))));
 
148
                        Assert.IsFalse(r.IsAmbiguous);
 
149
                        Assert.AreEqual(2, r.BestCandidate.Parameters.Count);
 
150
                }
 
151
                
 
152
                [Test]
 
153
                public void CallInvalidParamsDeclaration()
 
154
                {
 
155
                        OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList(typeof(int[,])));
 
156
                        Assert.AreEqual(OverloadResolutionErrors.ArgumentTypeMismatch, r.AddCandidate(MakeParamsMethod(typeof(int))));
 
157
                        Assert.IsFalse(r.BestCandidateIsExpandedForm);
 
158
                }
 
159
                
 
160
                [Test]
 
161
                public void PreferMethodWithoutOptionalParameters()
 
162
                {
 
163
                        var m1 = MakeMethod();
 
164
                        var m2 = MakeMethod(1);
 
165
                        
 
166
                        OverloadResolution r = new OverloadResolution(compilation, MakeArgumentList());
 
167
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m1));
 
168
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m2));
 
169
                        Assert.IsFalse(r.IsAmbiguous);
 
170
                        Assert.AreSame(m1, r.BestCandidate);
 
171
                }
 
172
                
 
173
                [Test]
 
174
                public void SkeetEvilOverloadResolution()
 
175
                {
 
176
                        // http://msmvps.com/blogs/jon_skeet/archive/2010/11/02/evil-code-overload-resolution-workaround.aspx
 
177
                        
 
178
                        // static void Foo<T>(T? ignored = default(T?)) where T : struct
 
179
                        var m1 = MakeUnresolvedMethod();
 
180
                        m1.TypeParameters.Add(new DefaultUnresolvedTypeParameter(EntityType.Method, 0, "T") { HasValueTypeConstraint = true });
 
181
                        m1.Parameters.Add(MakeOptionalParameter(
 
182
                                NullableType.Create(new TypeParameterReference(EntityType.Method, 0)),
 
183
                                "ignored"
 
184
                        ));
 
185
                        
 
186
                        // class ClassConstraint<T> where T : class {}
 
187
                        var classConstraint = new DefaultUnresolvedTypeDefinition(string.Empty, "ClassConstraint");
 
188
                        classConstraint.TypeParameters.Add(new DefaultUnresolvedTypeParameter(EntityType.TypeDefinition, 0, "T") { HasReferenceTypeConstraint = true });
 
189
                        
 
190
                        // static void Foo<T>(ClassConstraint<T> ignored = default(ClassConstraint<T>))
 
191
                        // where T : class
 
192
                        var m2 = MakeUnresolvedMethod();
 
193
                        m2.TypeParameters.Add(new DefaultUnresolvedTypeParameter(EntityType.Method, 0, "T") { HasReferenceTypeConstraint = true });
 
194
                        m2.Parameters.Add(MakeOptionalParameter(
 
195
                                new ParameterizedTypeReference(classConstraint, new[] { new TypeParameterReference(EntityType.Method, 0) }),
 
196
                                "ignored"
 
197
                        ));
 
198
                        
 
199
                        // static void Foo<T>()
 
200
                        var m3 = MakeUnresolvedMethod();
 
201
                        m3.TypeParameters.Add(new DefaultUnresolvedTypeParameter(EntityType.Method, 0, "T"));
 
202
                        
 
203
                        ICompilation compilation = TypeSystemHelper.CreateCompilation(classConstraint);
 
204
                        var context = new SimpleTypeResolveContext(compilation.MainAssembly);
 
205
                        IMethod resolvedM1 = (IMethod)m1.CreateResolved(context);
 
206
                        IMethod resolvedM2 = (IMethod)m2.CreateResolved(context);
 
207
                        IMethod resolvedM3 = (IMethod)m3.CreateResolved(context);
 
208
                        
 
209
                        // Call: Foo<int>();
 
210
                        OverloadResolution o;
 
211
                        o = new OverloadResolution(compilation, new ResolveResult[0], typeArguments: new[] { compilation.FindType(typeof(int)) });
 
212
                        Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(resolvedM1));
 
213
                        Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM2));
 
214
                        Assert.AreSame(resolvedM1, o.BestCandidate);
 
215
                        
 
216
                        // Call: Foo<string>();
 
217
                        o = new OverloadResolution(compilation, new ResolveResult[0], typeArguments: new[] { compilation.FindType(typeof(string)) });
 
218
                        Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM1));
 
219
                        Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(resolvedM2));
 
220
                        Assert.AreSame(resolvedM2, o.BestCandidate);
 
221
                        
 
222
                        // Call: Foo<int?>();
 
223
                        o = new OverloadResolution(compilation, new ResolveResult[0], typeArguments: new[] { compilation.FindType(typeof(int?)) });
 
224
                        Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM1));
 
225
                        Assert.AreEqual(OverloadResolutionErrors.ConstructedTypeDoesNotSatisfyConstraint, o.AddCandidate(resolvedM2));
 
226
                        Assert.AreEqual(OverloadResolutionErrors.None, o.AddCandidate(resolvedM3));
 
227
                        Assert.AreSame(resolvedM3, o.BestCandidate);
 
228
                }
 
229
                
 
230
                /// <summary>
 
231
                /// A lambda of the form "() => default(returnType)"
 
232
                /// </summary>
 
233
                class MockLambda : LambdaResolveResult
 
234
                {
 
235
                        IType inferredReturnType;
 
236
                        List<IParameter> parameters = new List<IParameter>();
 
237
                        
 
238
                        public MockLambda(IType returnType)
 
239
                        {
 
240
                                this.inferredReturnType = returnType;
 
241
                        }
 
242
                        
 
243
                        public override IList<IParameter> Parameters {
 
244
                                get { return parameters; }
 
245
                        }
 
246
                        
 
247
                        public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions)
 
248
                        {
 
249
                                return conversions.ImplicitConversion(inferredReturnType, returnType);
 
250
                        }
 
251
                        
 
252
                        public override bool IsImplicitlyTyped {
 
253
                                get { return false; }
 
254
                        }
 
255
                        
 
256
                        public override bool IsAnonymousMethod {
 
257
                                get { return false; }
 
258
                        }
 
259
                        
 
260
                        public override bool HasParameterList {
 
261
                                get { return true; }
 
262
                        }
 
263
                        
 
264
                        public override bool IsAsync {
 
265
                                get { return false; }
 
266
                        }
 
267
                        
 
268
                        public override ResolveResult Body {
 
269
                                get { throw new NotImplementedException(); }
 
270
                        }
 
271
                        
 
272
                        public override IType GetInferredReturnType(IType[] parameterTypes)
 
273
                        {
 
274
                                return inferredReturnType;
 
275
                        }
 
276
                }
 
277
                
 
278
                [Test]
 
279
                public void BetterConversionByLambdaReturnValue()
 
280
                {
 
281
                        var m1 = MakeMethod(typeof(Func<long>));
 
282
                        var m2 = MakeMethod(typeof(Func<int>));
 
283
                        
 
284
                        // M(() => default(byte));
 
285
                        ResolveResult[] args = {
 
286
                                new MockLambda(compilation.FindType(KnownTypeCode.Byte))
 
287
                        };
 
288
                        
 
289
                        OverloadResolution r = new OverloadResolution(compilation, args);
 
290
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m1));
 
291
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m2));
 
292
                        Assert.AreSame(m2, r.BestCandidate);
 
293
                        Assert.AreEqual(OverloadResolutionErrors.None, r.BestCandidateErrors);
 
294
                }
 
295
                
 
296
                [Test]
 
297
                public void BetterConversionByLambdaReturnValue_ExpressionTree()
 
298
                {
 
299
                        var m1 = MakeMethod(typeof(Func<long>));
 
300
                        var m2 = MakeMethod(typeof(Expression<Func<int>>));
 
301
                        
 
302
                        // M(() => default(byte));
 
303
                        ResolveResult[] args = {
 
304
                                new MockLambda(compilation.FindType(KnownTypeCode.Byte))
 
305
                        };
 
306
                        
 
307
                        OverloadResolution r = new OverloadResolution(compilation, args);
 
308
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m1));
 
309
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m2));
 
310
                        Assert.AreSame(m2, r.BestCandidate);
 
311
                        Assert.AreEqual(OverloadResolutionErrors.None, r.BestCandidateErrors);
 
312
                }
 
313
                
 
314
                [Test]
 
315
                public void Lambda_DelegateAndExpressionTreeOverloadsAreAmbiguous()
 
316
                {
 
317
                        var m1 = MakeMethod(typeof(Func<int>));
 
318
                        var m2 = MakeMethod(typeof(Expression<Func<int>>));
 
319
                        
 
320
                        // M(() => default(int));
 
321
                        ResolveResult[] args = {
 
322
                                new MockLambda(compilation.FindType(KnownTypeCode.Int32))
 
323
                        };
 
324
                        
 
325
                        OverloadResolution r = new OverloadResolution(compilation, args);
 
326
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m1));
 
327
                        Assert.AreEqual(OverloadResolutionErrors.None, r.AddCandidate(m2));
 
328
                        Assert.AreEqual(OverloadResolutionErrors.AmbiguousMatch, r.BestCandidateErrors);
 
329
                }
 
330
        }
 
331
}