Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Resolver/MethodGroupResolveResult.cs

Last change on this file was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

File size: 10.8 KB
Line 
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
19using System;
20using System.Collections.Generic;
21using System.Collections.ObjectModel;
22using System.Diagnostics;
23using System.Linq;
24using System.Text;
25using ICSharpCode.NRefactory.CSharp.TypeSystem;
26using ICSharpCode.NRefactory.Semantics;
27using ICSharpCode.NRefactory.TypeSystem;
28using ICSharpCode.NRefactory.TypeSystem.Implementation;
29
30namespace ICSharpCode.NRefactory.CSharp.Resolver
31{
32  /// <summary>
33  /// A method list that belongs to a declaring type.
34  /// </summary>
35  public class MethodListWithDeclaringType : List<IParameterizedMember>
36  {
37    readonly IType declaringType;
38   
39    /// <summary>
40    /// The declaring type.
41    /// </summary>
42    /// <remarks>
43    /// Not all methods in this list necessarily have this as their declaring type.
44    /// For example, this program:
45    /// <code>
46    ///  class Base {
47    ///    public virtual void M() {}
48    ///  }
49    ///  class Derived : Base {
50    ///    public override void M() {}
51    ///    public void M(int i) {}
52    ///  }
53    /// </code>
54    /// results in two lists:
55    ///  <c>new MethodListWithDeclaringType(Base) { Derived.M() }</c>,
56    ///  <c>new MethodListWithDeclaringType(Derived) { Derived.M(int) }</c>
57    /// </remarks>
58    public IType DeclaringType {
59      get { return declaringType; }
60    }
61   
62    public MethodListWithDeclaringType(IType declaringType)
63    {
64      this.declaringType = declaringType;
65    }
66   
67    public MethodListWithDeclaringType(IType declaringType, IEnumerable<IParameterizedMember> methods)
68      : base(methods)
69    {
70      this.declaringType = declaringType;
71    }
72  }
73 
74  /// <summary>
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.
79  /// </summary>
80  public class MethodGroupResolveResult : ResolveResult
81  {
82    readonly IList<MethodListWithDeclaringType> methodLists;
83    readonly IList<IType> typeArguments;
84    readonly ResolveResult targetResult;
85    readonly string methodName;
86   
87    public MethodGroupResolveResult(ResolveResult targetResult, string methodName, IList<MethodListWithDeclaringType> methods, IList<IType> typeArguments) : base(SpecialType.UnknownType)
88    {
89      if (methods == null)
90        throw new ArgumentNullException("methods");
91      this.targetResult = targetResult;
92      this.methodName = methodName;
93      this.methodLists = methods;
94      this.typeArguments = typeArguments ?? EmptyList<IType>.Instance;
95    }
96   
97    /// <summary>
98    /// Gets the resolve result for the target object.
99    /// </summary>
100    public ResolveResult TargetResult {
101      get { return targetResult; }
102    }
103   
104    /// <summary>
105    /// Gets the type of the reference to the target object.
106    /// </summary>
107    public IType TargetType {
108      get { return targetResult != null ? targetResult.Type : SpecialType.UnknownType; }
109    }
110   
111    /// <summary>
112    /// Gets the name of the methods in this group.
113    /// </summary>
114    public string MethodName {
115      get { return methodName; }
116    }
117   
118    /// <summary>
119    /// Gets the methods that were found.
120    /// This list does not include extension methods.
121    /// </summary>
122    public IEnumerable<IMethod> Methods {
123      get { return methodLists.SelectMany(m => m.Cast<IMethod>()); }
124    }
125   
126    /// <summary>
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.
130    /// </summary>
131    public IEnumerable<MethodListWithDeclaringType> MethodsGroupedByDeclaringType {
132      get { return methodLists; }
133    }
134   
135    /// <summary>
136    /// Gets the type arguments that were explicitly provided.
137    /// </summary>
138    public IList<IType> TypeArguments {
139      get { return typeArguments; }
140    }
141   
142    /// <summary>
143    /// List of extension methods, used to avoid re-calculating it in ResolveInvocation() when it was already
144    /// calculated by ResolveMemberAccess().
145    /// </summary>
146    internal List<List<IMethod>> extensionMethods;
147   
148    // the resolver is used to fetch extension methods on demand
149    internal CSharpResolver resolver;
150   
151    /// <summary>
152    /// Gets all candidate extension methods.
153    /// Note: this includes candidates that are not eligible due to an inapplicable
154    /// this argument.
155    /// The candidates will only be specialized if the type arguments were provided explicitly.
156    /// </summary>
157    /// <remarks>
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
161    /// new List {
162    ///    new List { all extensions from MoreExtensions },
163    ///    new List { all extensions from SomeExtensions }
164    /// }
165    /// </remarks>
166    public IEnumerable<IEnumerable<IMethod>> GetExtensionMethods()
167    {
168      if (resolver != null) {
169        Debug.Assert(extensionMethods == null);
170        try {
171          extensionMethods = resolver.GetExtensionMethods(methodName, typeArguments);
172        } finally {
173          resolver = null;
174        }
175      }
176      return extensionMethods ?? Enumerable.Empty<IEnumerable<IMethod>>();
177    }
178   
179    /// <summary>
180    /// Gets the eligible extension methods.
181    /// </summary>
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.
187    /// </param>
188    /// <remarks>
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
192    /// new List {
193    ///    new List { all extensions from MoreExtensions },
194    ///    new List { all extensions from SomeExtensions }
195    /// }
196    /// </remarks>
197    public IEnumerable<IEnumerable<IMethod>> GetEligibleExtensionMethods(bool substituteInferredTypes)
198    {
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)));
207            } else {
208              outputGroup.Add(method);
209            }
210          }
211        }
212        if (outputGroup.Count > 0)
213          result.Add(outputGroup);
214      }
215      return result;
216    }
217   
218    public override string ToString()
219    {
220      return string.Format("[{0} with {1} method(s)]", GetType().Name, this.Methods.Count());
221    }
222   
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)
228    {
229      Log.WriteLine("Performing overload resolution for " + this);
230      Log.WriteCollection("  Arguments: ", arguments);
231     
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;
237     
238      or.AddMethodLists(methodLists);
239     
240      if (allowExtensionMethods && !or.FoundApplicableCandidate) {
241        // No applicable match found, so let's try extension methods.
242       
243        var extensionMethods = this.GetExtensionMethods();
244       
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);
254          }
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;
260         
261          foreach (var g in extensionMethods) {
262            foreach (var method in g) {
263              Log.Indent();
264              OverloadResolutionErrors errors = extOr.AddCandidate(method);
265              Log.Unindent();
266              or.LogCandidateAddingResult("  Extension", method, errors);
267            }
268            if (extOr.FoundApplicableCandidate)
269              break;
270          }
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.
276            or = extOr;
277          }
278        }
279      }
280      Log.WriteLine("Overload resolution finished, best candidate is {0}.", or.GetBestCandidateWithSubstitutedTypeArguments());
281      return or;
282    }
283   
284    public override IEnumerable<ResolveResult> GetChildResults()
285    {
286      if (targetResult != null)
287        return new[] { targetResult };
288      else
289        return Enumerable.Empty<ResolveResult>();
290    }
291  }
292}
Note: See TracBrowser for help on using the repository browser.