|
|
|
@ -1530,7 +1530,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver |
|
|
|
MemberLookup lookup = CreateMemberLookup(); |
|
|
|
MemberLookup lookup = CreateMemberLookup(); |
|
|
|
ResolveResult result = lookup.Lookup(target, identifier, typeArguments, isInvocationTarget); |
|
|
|
ResolveResult result = lookup.Lookup(target, identifier, typeArguments, isInvocationTarget); |
|
|
|
if (result is UnknownMemberResolveResult) { |
|
|
|
if (result is UnknownMemberResolveResult) { |
|
|
|
var extensionMethods = GetExtensionMethods(target.Type, identifier, typeArguments); |
|
|
|
var extensionMethods = GetExtensionMethods(identifier, typeArguments); |
|
|
|
if (extensionMethods.Count > 0) { |
|
|
|
if (extensionMethods.Count > 0) { |
|
|
|
return new MethodGroupResolveResult(target, identifier, EmptyList<MethodListWithDeclaringType>.Instance, typeArguments) { |
|
|
|
return new MethodGroupResolveResult(target, identifier, EmptyList<MethodListWithDeclaringType>.Instance, typeArguments) { |
|
|
|
extensionMethods = extensionMethods |
|
|
|
extensionMethods = extensionMethods |
|
|
|
@ -1599,12 +1599,34 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver |
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region GetExtensionMethods
|
|
|
|
#region GetExtensionMethods
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Gets all extension methods that are available in the current context.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
/// <param name="name">Name of the extension method. Pass null to retrieve all extension methods.</param>
|
|
|
|
|
|
|
|
/// <param name="typeArguments">Explicitly provided type arguments.
|
|
|
|
|
|
|
|
/// An empty list will return all matching extension method definitions;
|
|
|
|
|
|
|
|
/// a non-empty list will return <see cref="SpecializedMethod"/>s for all extension methods
|
|
|
|
|
|
|
|
/// with the matching number of type parameters.</param>
|
|
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
|
|
/// The results are stored in nested lists because they are grouped by using scope.
|
|
|
|
|
|
|
|
/// That is, for "using SomeExtensions; namespace X { using MoreExtensions; ... }",
|
|
|
|
|
|
|
|
/// the return value will be
|
|
|
|
|
|
|
|
/// new List {
|
|
|
|
|
|
|
|
/// new List { all extensions from MoreExtensions },
|
|
|
|
|
|
|
|
/// new List { all extensions from SomeExtensions }
|
|
|
|
|
|
|
|
/// }
|
|
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
|
|
public List<List<IMethod>> GetExtensionMethods(string name = null, IList<IType> typeArguments = null) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return GetExtensionMethods(null, name, typeArguments); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// Gets the extension methods that are called 'name'
|
|
|
|
/// Gets the extension methods that are called 'name'
|
|
|
|
/// and are applicable with a first argument type of 'targetType'.
|
|
|
|
/// and are applicable with a first argument type of 'targetType'.
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="targetType">Type of the 'this' argument</param>
|
|
|
|
/// <param name="targetType">Type of the 'this' argument</param>
|
|
|
|
/// <param name="name">Name of the extension method</param>
|
|
|
|
/// <param name="name">Name of the extension method. Pass null to retrieve all extension methods.</param>
|
|
|
|
/// <param name="typeArguments">Explicitly provided type arguments.
|
|
|
|
/// <param name="typeArguments">Explicitly provided type arguments.
|
|
|
|
/// An empty list will return all matching extension method definitions;
|
|
|
|
/// An empty list will return all matching extension method definitions;
|
|
|
|
/// a non-empty list will return <see cref="SpecializedMethod"/>s for all extension methods
|
|
|
|
/// a non-empty list will return <see cref="SpecializedMethod"/>s for all extension methods
|
|
|
|
@ -1618,24 +1640,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver |
|
|
|
/// new List { all extensions from SomeExtensions }
|
|
|
|
/// new List { all extensions from SomeExtensions }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// </remarks>
|
|
|
|
/// </remarks>
|
|
|
|
public List<List<IMethod>> GetExtensionMethods(IType targetType, string name, IList<IType> typeArguments = null) |
|
|
|
public List<List<IMethod>> GetExtensionMethods(IType targetType, string name = null, IList<IType> typeArguments = null) |
|
|
|
{ |
|
|
|
{ |
|
|
|
List<List<IMethod>> extensionMethodGroups = new List<List<IMethod>>(); |
|
|
|
List<List<IMethod>> extensionMethodGroups = new List<List<IMethod>>(); |
|
|
|
foreach (var inputGroup in GetAllExtensionMethods()) { |
|
|
|
foreach (var inputGroup in GetAllExtensionMethods()) { |
|
|
|
List<IMethod> outputGroup = new List<IMethod>(); |
|
|
|
List<IMethod> outputGroup = new List<IMethod>(); |
|
|
|
foreach (var method in inputGroup) { |
|
|
|
foreach (var method in inputGroup) { |
|
|
|
if (method.Name != name) |
|
|
|
if (name != null && method.Name != name) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
if (typeArguments != null && typeArguments.Count > 0) { |
|
|
|
if (typeArguments != null && typeArguments.Count > 0) { |
|
|
|
if (method.TypeParameters.Count != typeArguments.Count) |
|
|
|
if (method.TypeParameters.Count != typeArguments.Count) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
SpecializedMethod sm = new SpecializedMethod(method.DeclaringType, method, typeArguments); |
|
|
|
SpecializedMethod sm = new SpecializedMethod(method.DeclaringType, method, typeArguments); |
|
|
|
// TODO: verify targetType
|
|
|
|
if (IsEligibleExtensionMethod(targetType, method, false)) |
|
|
|
outputGroup.Add(sm); |
|
|
|
outputGroup.Add(sm); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// TODO: verify targetType
|
|
|
|
if (IsEligibleExtensionMethod(targetType, method, true)) |
|
|
|
outputGroup.Add(method); |
|
|
|
outputGroup.Add(method); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (outputGroup.Count > 0) |
|
|
|
if (outputGroup.Count > 0) |
|
|
|
@ -1644,22 +1666,34 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver |
|
|
|
return extensionMethodGroups; |
|
|
|
return extensionMethodGroups; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public List<List<IMethod>> GetAllExtensionMethods(IType targetType) |
|
|
|
bool IsEligibleExtensionMethod(IType targetType, IMethod method, bool useTypeInference) |
|
|
|
{ |
|
|
|
{ |
|
|
|
List<List<IMethod>> extensionMethodGroups = new List<List<IMethod>>(); |
|
|
|
if (targetType == null) |
|
|
|
foreach (var inputGroup in GetAllExtensionMethods()) { |
|
|
|
return true; |
|
|
|
List<IMethod> outputGroup = new List<IMethod>(); |
|
|
|
if (method.Parameters.Count == 0) |
|
|
|
foreach (var method in inputGroup) { |
|
|
|
return false; |
|
|
|
outputGroup.Add(method); |
|
|
|
IType thisParameterType = method.Parameters[0].Type; |
|
|
|
|
|
|
|
if (useTypeInference && method.TypeParameters.Count > 0) { |
|
|
|
|
|
|
|
// We need to infer type arguments from targetType:
|
|
|
|
|
|
|
|
TypeInference ti = new TypeInference(compilation, conversions); |
|
|
|
|
|
|
|
ResolveResult[] arguments = { new ResolveResult(targetType) }; |
|
|
|
|
|
|
|
IType[] parameterTypes = { method.Parameters[0].Type }; |
|
|
|
|
|
|
|
bool success; |
|
|
|
|
|
|
|
IType[] inferredTypes = ti.InferTypeArguments(method.TypeParameters, arguments, parameterTypes, out success); |
|
|
|
|
|
|
|
var substitution = new TypeParameterSubstitution(null, inferredTypes); |
|
|
|
|
|
|
|
// Validate that the types that could be inferred (aren't unknown) satisfy the constraints:
|
|
|
|
|
|
|
|
for (int i = 0; i < inferredTypes.Length; i++) { |
|
|
|
|
|
|
|
if (inferredTypes[i].Kind != TypeKind.Unknown && inferredTypes[i].Kind != TypeKind.UnboundTypeArgument) { |
|
|
|
|
|
|
|
if (!OverloadResolution.ValidateConstraints(method.TypeParameters[i], inferredTypes[i], substitution, conversions)) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (outputGroup.Count > 0) |
|
|
|
thisParameterType = thisParameterType.AcceptVisitor(substitution); |
|
|
|
extensionMethodGroups.Add(outputGroup); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
return extensionMethodGroups; |
|
|
|
Conversion c = conversions.ImplicitConversion(targetType, thisParameterType); |
|
|
|
|
|
|
|
return c.IsValid && (c.IsIdentityConversion || c.IsReferenceConversion || c.IsBoxingConversion); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// Gets all extension methods available in the current using scope.
|
|
|
|
/// Gets all extension methods available in the current using scope.
|
|
|
|
/// This list includes unaccessible
|
|
|
|
/// This list includes unaccessible
|
|
|
|
|