1
ļ»æ// Copyright (c) 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
32
public class MethodListWithDeclaringType : List<IParameterizedMember>
34
readonly IType declaringType;
36
public IType DeclaringType {
37
get { return declaringType; }
40
public MethodListWithDeclaringType(IType declaringType)
42
this.declaringType = declaringType;
45
public MethodListWithDeclaringType(IType declaringType, IEnumerable<IParameterizedMember> methods)
48
this.declaringType = declaringType;
53
/// Represents a group of methods.
55
public class MethodGroupResolveResult : ResolveResult
57
readonly IList<MethodListWithDeclaringType> methodLists;
58
readonly IList<IType> typeArguments;
59
readonly ResolveResult targetResult;
60
readonly string methodName;
62
public MethodGroupResolveResult(ResolveResult targetResult, string methodName, IList<MethodListWithDeclaringType> methods, IList<IType> typeArguments) : base(SpecialType.UnknownType)
64
if (targetResult == null)
65
throw new ArgumentNullException("targetResult");
67
throw new ArgumentNullException("methods");
68
this.targetResult = targetResult;
69
this.methodName = methodName;
70
this.methodLists = methods;
71
this.typeArguments = typeArguments ?? EmptyList<IType>.Instance;
75
/// Gets the resolve result for the target object.
77
public ResolveResult TargetResult {
78
get { return targetResult; }
82
/// Gets the type of the reference to the target object.
84
public IType TargetType {
85
get { return targetResult.Type; }
89
/// Gets the name of the methods in this group.
91
public string MethodName {
92
get { return methodName; }
96
/// Gets the methods that were found.
97
/// This list does not include extension methods.
99
public IEnumerable<IMethod> Methods {
100
get { return methodLists.SelectMany(m => m.Cast<IMethod>()); }
104
/// Gets the methods that were found, grouped by their declaring type.
105
/// This list does not include extension methods.
106
/// Base types come first in the list.
108
public IEnumerable<MethodListWithDeclaringType> MethodsGroupedByDeclaringType {
109
get { return methodLists; }
113
/// Gets the type arguments that were explicitly provided.
115
public IList<IType> TypeArguments {
116
get { return typeArguments; }
120
/// List of extension methods, used to avoid re-calculating it in ResolveInvocation() when it was already
121
/// calculated by ResolveMemberAccess().
123
internal List<List<IMethod>> extensionMethods;
125
// the resolver is used to fetch extension methods on demand
126
internal CSharpResolver resolver;
129
/// Gets all candidate extension methods.
130
/// Note: this includes candidates that are not eligible due to an inapplicable
134
/// The results are stored in nested lists because they are grouped by using scope.
135
/// That is, for "using SomeExtensions; namespace X { using MoreExtensions; ... }",
136
/// the return value will be
138
/// new List { all extensions from MoreExtensions },
139
/// new List { all extensions from SomeExtensions }
142
public IEnumerable<IEnumerable<IMethod>> GetExtensionMethods()
144
if (resolver != null) {
145
Debug.Assert(extensionMethods == null);
147
extensionMethods = resolver.GetExtensionMethods(methodName, typeArguments);
152
return extensionMethods ?? Enumerable.Empty<IEnumerable<IMethod>>();
155
public IEnumerable<IEnumerable<IMethod>> GetEligibleExtensionMethods(bool substituteInferredTypes)
157
var result = new List<List<IMethod>>();
158
foreach (var methodGroup in GetExtensionMethods()) {
159
var outputGroup = new List<IMethod>();
160
foreach (var method in methodGroup) {
161
IType[] inferredTypes;
162
if (CSharpResolver.IsEligibleExtensionMethod(this.TargetType, method, true, out inferredTypes)) {
163
if (substituteInferredTypes && inferredTypes != null) {
164
outputGroup.Add(new SpecializedMethod(method, new TypeParameterSubstitution(null, inferredTypes)));
166
outputGroup.Add(method);
170
if (outputGroup.Count > 0)
171
result.Add(outputGroup);
176
public override string ToString()
178
return string.Format("[{0} with {1} method(s)]", GetType().Name, this.Methods.Count());
181
public OverloadResolution PerformOverloadResolution(ICompilation compilation, ResolveResult[] arguments, string[] argumentNames = null, bool allowExtensionMethods = true, bool allowExpandingParams = true, CSharpConversions conversions = null)
183
Log.WriteLine("Performing overload resolution for " + this);
184
Log.WriteCollection(" Arguments: ", arguments);
186
var typeArgumentArray = this.TypeArguments.ToArray();
187
OverloadResolution or = new OverloadResolution(compilation, arguments, argumentNames, typeArgumentArray, conversions);
188
or.AllowExpandingParams = allowExpandingParams;
190
or.AddMethodLists(methodLists);
192
if (allowExtensionMethods && !or.FoundApplicableCandidate) {
193
// No applicable match found, so let's try extension methods.
195
var extensionMethods = this.GetExtensionMethods();
197
if (extensionMethods.Any()) {
198
Log.WriteLine("No candidate is applicable, trying {0} extension methods groups...", extensionMethods.Count());
199
ResolveResult[] extArguments = new ResolveResult[arguments.Length + 1];
200
extArguments[0] = new ResolveResult(this.TargetType);
201
arguments.CopyTo(extArguments, 1);
202
string[] extArgumentNames = null;
203
if (argumentNames != null) {
204
extArgumentNames = new string[argumentNames.Length + 1];
205
argumentNames.CopyTo(extArgumentNames, 1);
207
var extOr = new OverloadResolution(compilation, extArguments, extArgumentNames, typeArgumentArray, conversions);
208
extOr.AllowExpandingParams = allowExpandingParams;
209
extOr.IsExtensionMethodInvocation = true;
211
foreach (var g in extensionMethods) {
212
foreach (var method in g) {
214
OverloadResolutionErrors errors = extOr.AddCandidate(method);
216
or.LogCandidateAddingResult(" Extension", method, errors);
218
if (extOr.FoundApplicableCandidate)
221
// For the lack of a better comparison function (the one within OverloadResolution
222
// cannot be used as it depends on the argument set):
223
if (extOr.FoundApplicableCandidate || or.BestCandidate == null) {
224
// Consider an extension method result better than the normal result only
225
// if it's applicable; or if there is no normal result.
230
Log.WriteLine("Overload resolution finished, best candidate is {0}.", or.GetBestCandidateWithSubstitutedTypeArguments());
234
public override IEnumerable<ResolveResult> GetChildResults()
236
if (targetResult != null)
237
return new[] { targetResult };
239
return Enumerable.Empty<ResolveResult>();