PageRenderTime 1584ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/MethodGroupResolveResult.cs

http://github.com/icsharpcode/ILSpy
C# | 292 lines | 157 code | 26 blank | 109 comment | 23 complexity | c772bc28180b62a13780f35b14c11061 MD5 | raw file
Possible License(s): LGPL-2.1, MIT, CC-BY-SA-3.0
  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. using System;
  19. using System.Collections.Generic;
  20. using System.Collections.ObjectModel;
  21. using System.Diagnostics;
  22. using System.Linq;
  23. using System.Text;
  24. using ICSharpCode.NRefactory.CSharp.TypeSystem;
  25. using ICSharpCode.NRefactory.Semantics;
  26. using ICSharpCode.NRefactory.TypeSystem;
  27. using ICSharpCode.NRefactory.TypeSystem.Implementation;
  28. namespace ICSharpCode.NRefactory.CSharp.Resolver
  29. {
  30. /// <summary>
  31. /// A method list that belongs to a declaring type.
  32. /// </summary>
  33. public class MethodListWithDeclaringType : List<IParameterizedMember>
  34. {
  35. readonly IType declaringType;
  36. /// <summary>
  37. /// The declaring type.
  38. /// </summary>
  39. /// <remarks>
  40. /// Not all methods in this list necessarily have this as their declaring type.
  41. /// For example, this program:
  42. /// <code>
  43. /// class Base {
  44. /// public virtual void M() {}
  45. /// }
  46. /// class Derived : Base {
  47. /// public override void M() {}
  48. /// public void M(int i) {}
  49. /// }
  50. /// </code>
  51. /// results in two lists:
  52. /// <c>new MethodListWithDeclaringType(Base) { Derived.M() }</c>,
  53. /// <c>new MethodListWithDeclaringType(Derived) { Derived.M(int) }</c>
  54. /// </remarks>
  55. public IType DeclaringType {
  56. get { return declaringType; }
  57. }
  58. public MethodListWithDeclaringType(IType declaringType)
  59. {
  60. this.declaringType = declaringType;
  61. }
  62. public MethodListWithDeclaringType(IType declaringType, IEnumerable<IParameterizedMember> methods)
  63. : base(methods)
  64. {
  65. this.declaringType = declaringType;
  66. }
  67. }
  68. /// <summary>
  69. /// Represents a group of methods.
  70. /// A method reference used to create a delegate is resolved to a MethodGroupResolveResult.
  71. /// The MethodGroupResolveResult has no type.
  72. /// To retrieve the delegate type or the chosen overload, look at the method group conversion.
  73. /// </summary>
  74. public class MethodGroupResolveResult : ResolveResult
  75. {
  76. readonly IList<MethodListWithDeclaringType> methodLists;
  77. readonly IList<IType> typeArguments;
  78. readonly ResolveResult targetResult;
  79. readonly string methodName;
  80. public MethodGroupResolveResult(ResolveResult targetResult, string methodName, IList<MethodListWithDeclaringType> methods, IList<IType> typeArguments) : base(SpecialType.UnknownType)
  81. {
  82. if (methods == null)
  83. throw new ArgumentNullException("methods");
  84. this.targetResult = targetResult;
  85. this.methodName = methodName;
  86. this.methodLists = methods;
  87. this.typeArguments = typeArguments ?? EmptyList<IType>.Instance;
  88. }
  89. /// <summary>
  90. /// Gets the resolve result for the target object.
  91. /// </summary>
  92. public ResolveResult TargetResult {
  93. get { return targetResult; }
  94. }
  95. /// <summary>
  96. /// Gets the type of the reference to the target object.
  97. /// </summary>
  98. public IType TargetType {
  99. get { return targetResult != null ? targetResult.Type : SpecialType.UnknownType; }
  100. }
  101. /// <summary>
  102. /// Gets the name of the methods in this group.
  103. /// </summary>
  104. public string MethodName {
  105. get { return methodName; }
  106. }
  107. /// <summary>
  108. /// Gets the methods that were found.
  109. /// This list does not include extension methods.
  110. /// </summary>
  111. public IEnumerable<IMethod> Methods {
  112. get { return methodLists.SelectMany(m => m.Cast<IMethod>()); }
  113. }
  114. /// <summary>
  115. /// Gets the methods that were found, grouped by their declaring type.
  116. /// This list does not include extension methods.
  117. /// Base types come first in the list.
  118. /// </summary>
  119. public IEnumerable<MethodListWithDeclaringType> MethodsGroupedByDeclaringType {
  120. get { return methodLists; }
  121. }
  122. /// <summary>
  123. /// Gets the type arguments that were explicitly provided.
  124. /// </summary>
  125. public IList<IType> TypeArguments {
  126. get { return typeArguments; }
  127. }
  128. /// <summary>
  129. /// List of extension methods, used to avoid re-calculating it in ResolveInvocation() when it was already
  130. /// calculated by ResolveMemberAccess().
  131. /// </summary>
  132. internal List<List<IMethod>> extensionMethods;
  133. // the resolver is used to fetch extension methods on demand
  134. internal CSharpResolver resolver;
  135. /// <summary>
  136. /// Gets all candidate extension methods.
  137. /// Note: this includes candidates that are not eligible due to an inapplicable
  138. /// this argument.
  139. /// The candidates will only be specialized if the type arguments were provided explicitly.
  140. /// </summary>
  141. /// <remarks>
  142. /// The results are stored in nested lists because they are grouped by using scope.
  143. /// That is, for "using SomeExtensions; namespace X { using MoreExtensions; ... }",
  144. /// the return value will be
  145. /// new List {
  146. /// new List { all extensions from MoreExtensions },
  147. /// new List { all extensions from SomeExtensions }
  148. /// }
  149. /// </remarks>
  150. public IEnumerable<IEnumerable<IMethod>> GetExtensionMethods()
  151. {
  152. if (resolver != null) {
  153. Debug.Assert(extensionMethods == null);
  154. try {
  155. extensionMethods = resolver.GetExtensionMethods(methodName, typeArguments);
  156. } finally {
  157. resolver = null;
  158. }
  159. }
  160. return extensionMethods ?? Enumerable.Empty<IEnumerable<IMethod>>();
  161. }
  162. /// <summary>
  163. /// Gets the eligible extension methods.
  164. /// </summary>
  165. /// <param name="substituteInferredTypes">
  166. /// Specifies whether to produce a <see cref="SpecializedMethod"/>
  167. /// when type arguments could be inferred from <see cref="TargetType"/>.
  168. /// This setting is only used for inferred types and has no effect if the type parameters are
  169. /// specified explicitly.
  170. /// </param>
  171. /// <remarks>
  172. /// The results are stored in nested lists because they are grouped by using scope.
  173. /// That is, for "using SomeExtensions; namespace X { using MoreExtensions; ... }",
  174. /// the return value will be
  175. /// new List {
  176. /// new List { all extensions from MoreExtensions },
  177. /// new List { all extensions from SomeExtensions }
  178. /// }
  179. /// </remarks>
  180. public IEnumerable<IEnumerable<IMethod>> GetEligibleExtensionMethods(bool substituteInferredTypes)
  181. {
  182. var result = new List<List<IMethod>>();
  183. foreach (var methodGroup in GetExtensionMethods()) {
  184. var outputGroup = new List<IMethod>();
  185. foreach (var method in methodGroup) {
  186. IType[] inferredTypes;
  187. if (CSharpResolver.IsEligibleExtensionMethod(this.TargetType, method, true, out inferredTypes)) {
  188. if (substituteInferredTypes && inferredTypes != null) {
  189. outputGroup.Add(method.Specialize(new TypeParameterSubstitution(null, inferredTypes)));
  190. } else {
  191. outputGroup.Add(method);
  192. }
  193. }
  194. }
  195. if (outputGroup.Count > 0)
  196. result.Add(outputGroup);
  197. }
  198. return result;
  199. }
  200. public override string ToString()
  201. {
  202. return string.Format("[{0} with {1} method(s)]", GetType().Name, this.Methods.Count());
  203. }
  204. public OverloadResolution PerformOverloadResolution(ICompilation compilation, ResolveResult[] arguments, string[] argumentNames = null,
  205. bool allowExtensionMethods = true,
  206. bool allowExpandingParams = true,
  207. bool allowOptionalParameters = true,
  208. bool checkForOverflow = false, CSharpConversions conversions = null)
  209. {
  210. Log.WriteLine("Performing overload resolution for " + this);
  211. Log.WriteCollection(" Arguments: ", arguments);
  212. var typeArgumentArray = this.TypeArguments.ToArray();
  213. OverloadResolution or = new OverloadResolution(compilation, arguments, argumentNames, typeArgumentArray, conversions);
  214. or.AllowExpandingParams = allowExpandingParams;
  215. or.AllowOptionalParameters = allowOptionalParameters;
  216. or.CheckForOverflow = checkForOverflow;
  217. or.AddMethodLists(methodLists);
  218. if (allowExtensionMethods && !or.FoundApplicableCandidate) {
  219. // No applicable match found, so let's try extension methods.
  220. var extensionMethods = this.GetExtensionMethods();
  221. if (extensionMethods.Any()) {
  222. Log.WriteLine("No candidate is applicable, trying {0} extension methods groups...", extensionMethods.Count());
  223. ResolveResult[] extArguments = new ResolveResult[arguments.Length + 1];
  224. extArguments[0] = new ResolveResult(this.TargetType);
  225. arguments.CopyTo(extArguments, 1);
  226. string[] extArgumentNames = null;
  227. if (argumentNames != null) {
  228. extArgumentNames = new string[argumentNames.Length + 1];
  229. argumentNames.CopyTo(extArgumentNames, 1);
  230. }
  231. var extOr = new OverloadResolution(compilation, extArguments, extArgumentNames, typeArgumentArray, conversions);
  232. extOr.AllowExpandingParams = allowExpandingParams;
  233. extOr.AllowOptionalParameters = allowOptionalParameters;
  234. extOr.IsExtensionMethodInvocation = true;
  235. extOr.CheckForOverflow = checkForOverflow;
  236. foreach (var g in extensionMethods) {
  237. foreach (var method in g) {
  238. Log.Indent();
  239. OverloadResolutionErrors errors = extOr.AddCandidate(method);
  240. Log.Unindent();
  241. or.LogCandidateAddingResult(" Extension", method, errors);
  242. }
  243. if (extOr.FoundApplicableCandidate)
  244. break;
  245. }
  246. // For the lack of a better comparison function (the one within OverloadResolution
  247. // cannot be used as it depends on the argument set):
  248. if (extOr.FoundApplicableCandidate || or.BestCandidate == null) {
  249. // Consider an extension method result better than the normal result only
  250. // if it's applicable; or if there is no normal result.
  251. or = extOr;
  252. }
  253. }
  254. }
  255. Log.WriteLine("Overload resolution finished, best candidate is {0}.", or.GetBestCandidateWithSubstitutedTypeArguments());
  256. return or;
  257. }
  258. public override IEnumerable<ResolveResult> GetChildResults()
  259. {
  260. if (targetResult != null)
  261. return new[] { targetResult };
  262. else
  263. return Enumerable.Empty<ResolveResult>();
  264. }
  265. }
  266. }