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.
20
using System.Collections.Generic;
21
using System.Collections.ObjectModel;
22
using System.Diagnostics;
25
using ICSharpCode.NRefactory.CSharp.TypeSystem;
26
using ICSharpCode.NRefactory.Semantics;
27
using ICSharpCode.NRefactory.TypeSystem;
28
using ICSharpCode.NRefactory.TypeSystem.Implementation;
30
namespace ICSharpCode.NRefactory.CSharp.Resolver
33
/// A method list that belongs to a declaring type.
35
public class MethodListWithDeclaringType : List<IParameterizedMember>
37
readonly IType declaringType;
40
/// The declaring type.
43
/// Not all methods in this list necessarily have this as their declaring type.
44
/// For example, this program:
47
/// public virtual void M() {}
49
/// class Derived : Base {
50
/// public override void M() {}
51
/// public void M(int i) {}
54
/// results in two lists:
55
/// <c>new MethodListWithDeclaringType(Base) { Derived.M() }</c>,
56
/// <c>new MethodListWithDeclaringType(Derived) { Derived.M(int) }</c>
58
public IType DeclaringType {
59
get { return declaringType; }
62
public MethodListWithDeclaringType(IType declaringType)
64
this.declaringType = declaringType;
67
public MethodListWithDeclaringType(IType declaringType, IEnumerable<IParameterizedMember> methods)
70
this.declaringType = declaringType;
75
/// Represents a group of methods.
76
/// A method reference used to create a delegate is resolved to a MethodGroupResolveResult.
77
/// The MethodGroupResolveResult has no type.
78
/// To retrieve the delegate type or the chosen overload, look at the method group conversion.
80
public class MethodGroupResolveResult : ResolveResult
82
readonly IList<MethodListWithDeclaringType> methodLists;
83
readonly IList<IType> typeArguments;
84
readonly ResolveResult targetResult;
85
readonly string methodName;
87
public MethodGroupResolveResult(ResolveResult targetResult, string methodName, IList<MethodListWithDeclaringType> methods, IList<IType> typeArguments) : base(SpecialType.UnknownType)
90
throw new ArgumentNullException("methods");
91
this.targetResult = targetResult;
92
this.methodName = methodName;
93
this.methodLists = methods;
94
this.typeArguments = typeArguments ?? EmptyList<IType>.Instance;
98
/// Gets the resolve result for the target object.
100
public ResolveResult TargetResult {
101
get { return targetResult; }
105
/// Gets the type of the reference to the target object.
107
public IType TargetType {
108
get { return targetResult != null ? targetResult.Type : SpecialType.UnknownType; }
112
/// Gets the name of the methods in this group.
114
public string MethodName {
115
get { return methodName; }
119
/// Gets the methods that were found.
120
/// This list does not include extension methods.
122
public IEnumerable<IMethod> Methods {
123
get { return methodLists.SelectMany(m => m.Cast<IMethod>()); }
127
/// Gets the methods that were found, grouped by their declaring type.
128
/// This list does not include extension methods.
129
/// Base types come first in the list.
131
public IEnumerable<MethodListWithDeclaringType> MethodsGroupedByDeclaringType {
132
get { return methodLists; }
136
/// Gets the type arguments that were explicitly provided.
138
public IList<IType> TypeArguments {
139
get { return typeArguments; }
143
/// List of extension methods, used to avoid re-calculating it in ResolveInvocation() when it was already
144
/// calculated by ResolveMemberAccess().
146
internal List<List<IMethod>> extensionMethods;
148
// the resolver is used to fetch extension methods on demand
149
internal CSharpResolver resolver;
152
/// Gets all candidate extension methods.
153
/// Note: this includes candidates that are not eligible due to an inapplicable
155
/// The candidates will only be specialized if the type arguments were provided explicitly.
158
/// The results are stored in nested lists because they are grouped by using scope.
159
/// That is, for "using SomeExtensions; namespace X { using MoreExtensions; ... }",
160
/// the return value will be
162
/// new List { all extensions from MoreExtensions },
163
/// new List { all extensions from SomeExtensions }
166
public IEnumerable<IEnumerable<IMethod>> GetExtensionMethods()
168
if (resolver != null) {
169
Debug.Assert(extensionMethods == null);
171
extensionMethods = resolver.GetExtensionMethods(methodName, typeArguments);
176
return extensionMethods ?? Enumerable.Empty<IEnumerable<IMethod>>();
180
/// Gets the eligible extension methods.
182
/// <param name="substituteInferredTypes">
183
/// Specifies whether to produce a <see cref="SpecializedMethod"/>
184
/// when type arguments could be inferred from <see cref="TargetType"/>.
185
/// This setting is only used for inferred types and has no effect if the type parameters are
186
/// specified explicitly.
189
/// The results are stored in nested lists because they are grouped by using scope.
190
/// That is, for "using SomeExtensions; namespace X { using MoreExtensions; ... }",
191
/// the return value will be
193
/// new List { all extensions from MoreExtensions },
194
/// new List { all extensions from SomeExtensions }
197
public IEnumerable<IEnumerable<IMethod>> GetEligibleExtensionMethods(bool substituteInferredTypes)
199
var result = new List<List<IMethod>>();
200
foreach (var methodGroup in GetExtensionMethods()) {
201
var outputGroup = new List<IMethod>();
202
foreach (var method in methodGroup) {
203
IType[] inferredTypes;
204
if (CSharpResolver.IsEligibleExtensionMethod(this.TargetType, method, true, out inferredTypes)) {
205
if (substituteInferredTypes && inferredTypes != null) {
206
outputGroup.Add(method.Specialize(new TypeParameterSubstitution(null, inferredTypes)));
208
outputGroup.Add(method);
212
if (outputGroup.Count > 0)
213
result.Add(outputGroup);
218
public override string ToString()
220
return string.Format("[{0} with {1} method(s)]", GetType().Name, this.Methods.Count());
223
public OverloadResolution PerformOverloadResolution(ICompilation compilation, ResolveResult[] arguments, string[] argumentNames = null,
224
bool allowExtensionMethods = true,
225
bool allowExpandingParams = true,
226
bool allowOptionalParameters = true,
227
bool checkForOverflow = false, CSharpConversions conversions = null)
229
Log.WriteLine("Performing overload resolution for " + this);
230
Log.WriteCollection(" Arguments: ", arguments);
232
var typeArgumentArray = this.TypeArguments.ToArray();
233
OverloadResolution or = new OverloadResolution(compilation, arguments, argumentNames, typeArgumentArray, conversions);
234
or.AllowExpandingParams = allowExpandingParams;
235
or.AllowOptionalParameters = allowOptionalParameters;
236
or.CheckForOverflow = checkForOverflow;
238
or.AddMethodLists(methodLists);
240
if (allowExtensionMethods && !or.FoundApplicableCandidate) {
241
// No applicable match found, so let's try extension methods.
243
var extensionMethods = this.GetExtensionMethods();
245
if (extensionMethods.Any()) {
246
Log.WriteLine("No candidate is applicable, trying {0} extension methods groups...", extensionMethods.Count());
247
ResolveResult[] extArguments = new ResolveResult[arguments.Length + 1];
248
extArguments[0] = new ResolveResult(this.TargetType);
249
arguments.CopyTo(extArguments, 1);
250
string[] extArgumentNames = null;
251
if (argumentNames != null) {
252
extArgumentNames = new string[argumentNames.Length + 1];
253
argumentNames.CopyTo(extArgumentNames, 1);
255
var extOr = new OverloadResolution(compilation, extArguments, extArgumentNames, typeArgumentArray, conversions);
256
extOr.AllowExpandingParams = allowExpandingParams;
257
extOr.AllowOptionalParameters = allowOptionalParameters;
258
extOr.IsExtensionMethodInvocation = true;
259
extOr.CheckForOverflow = checkForOverflow;
261
foreach (var g in extensionMethods) {
262
foreach (var method in g) {
264
OverloadResolutionErrors errors = extOr.AddCandidate(method);
266
or.LogCandidateAddingResult(" Extension", method, errors);
268
if (extOr.FoundApplicableCandidate)
271
// For the lack of a better comparison function (the one within OverloadResolution
272
// cannot be used as it depends on the argument set):
273
if (extOr.FoundApplicableCandidate || or.BestCandidate == null) {
274
// Consider an extension method result better than the normal result only
275
// if it's applicable; or if there is no normal result.
280
Log.WriteLine("Overload resolution finished, best candidate is {0}.", or.GetBestCandidateWithSubstitutedTypeArguments());
284
public override IEnumerable<ResolveResult> GetChildResults()
286
if (targetResult != null)
287
return new[] { targetResult };
289
return Enumerable.Empty<ResolveResult>();