// The Nova Project by Ken Beckett.
// Copyright (C) 2007-2012 Inevitable Software, all rights reserved.
// Released under the Common Development and Distribution License, CDDL-1.0: http://opensource.org/licenses/cddl1.php
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using Mono.Cecil;
using Mono.Collections.Generic;
using Nova.Parsing;
using Nova.Rendering;
using Nova.Resolving;
using Nova.Utilities;
namespace Nova.CodeDOM
{
/// <summary>
/// Represents a reference to a <see cref="MethodDeclBase"/> (common base of <see cref="MethodDecl"/>,
/// <see cref="GenericMethodDecl"/>, <see cref="ConstructorDecl"/>, <see cref="DestructorDecl"/>),
/// <see cref="AnonymousMethod"/>, or <see cref="MethodDefinition"/>/<see cref="MethodInfo"/>.
/// </summary>
/// <remarks>
/// Instead of having a derived GenericMethodRef, this class supports type arguments directly.
/// This is because <see cref="ConstructorRef"/> (which is derived from this class) also needs type argument
/// support (even though a <see cref="ConstructorDecl"/> doesn't have type parameters, constructors for generic
/// types still need type arguments when they're referenced). Furthermore, <see cref="MethodRef"/> can be treated
/// as a delegate type, such as being passed to a method parameter of delegate type, so it is derived from
/// <see cref="TypeRefBase"/>, which provides the required type argument support (the array support isn't used).
/// </remarks>
public class MethodRef : TypeRefBase
{
#region /* FIELDS */
/// <summary>
/// True if the type arguments are inferred.
/// </summary>
public bool HasInferredTypeArguments;
#endregion
#region /* CONSTRUCTORS */
/// <summary>
/// Create a <see cref="MethodRef"/> from a <see cref="MethodDeclBase"/>.
/// </summary>
public MethodRef(MethodDeclBase methodDeclBase, bool isFirstOnLine, ChildList<Expression> typeArguments)
: base(methodDeclBase, isFirstOnLine)
{
// If the method is generic, and no type arguments were specified, do NOT default any (they will be inferred).
// Unlike nested types, methods of generic types are not considered generic if they don't have any local type
// arguments, and generic methods never include type arguments of generic enclosing types (presumably, when
// assigned to a delegate, any type arguments of generic enclosing types will be included in the object reference
// associated with the delegate).
// Constructors of generic types are also not generic methods, however the type arguments associated with their
// declaring type must be supplied when they are invoked - these are defaulted in ConstructorRef if omitted.
TypeArguments = typeArguments;
}
/// <summary>
/// Create a <see cref="MethodRef"/> from a <see cref="MethodDeclBase"/>.
/// </summary>
public MethodRef(MethodDeclBase methodDeclBase, bool isFirstOnLine)
: base(methodDeclBase, isFirstOnLine)
{ }
/// <summary>
/// Create a <see cref="MethodRef"/> from a <see cref="MethodDeclBase"/>.
/// </summary>
public MethodRef(MethodDeclBase methodDeclBase)
: base(methodDeclBase, false)
{ }
/// <summary>
/// Create a <see cref="MethodRef"/> from a <see cref="MethodDeclBase"/>.
/// </summary>
public MethodRef(MethodDeclBase methodDeclBase, ChildList<Expression> typeArguments)
: this(methodDeclBase, false, typeArguments)
{ }
/// <summary>
/// Create a <see cref="MethodRef"/> from a <see cref="MethodDeclBase"/>.
/// </summary>
public MethodRef(MethodDeclBase methodBase, bool isFirstOnLine, params Expression[] typeArguments)
: this(methodBase, isFirstOnLine, ((typeArguments != null && typeArguments.Length > 0) ? new ChildList<Expression>(typeArguments) : null))
{ }
/// <summary>
/// Create a <see cref="MethodRef"/> from a <see cref="MethodDeclBase"/>.
/// </summary>
public MethodRef(MethodDeclBase methodBase, params Expression[] typeArguments)
: this(methodBase, false, ((typeArguments != null && typeArguments.Length > 0) ? new ChildList<Expression>(typeArguments) : null))
{ }
/// <summary>
/// Create a <see cref="MethodRef"/> from a <see cref="MethodDefinition"/>.
/// </summary>
public MethodRef(MethodDefinition methodDefinition, bool isFirstOnLine, ChildList<Expression> typeArguments)
: base(methodDefinition, isFirstOnLine)
{
// If the method is generic, and no type arguments were specified, do NOT default any (they will be inferred).
// Unlike nested types, methods of generic types are not considered generic if they don't have any local type
// arguments, and generic methods never include type arguments of generic enclosing types (presumably, when
// assigned to a delegate, any type arguments of generic enclosing types will be included in the object reference
// associated with the delegate).
TypeArguments = typeArguments;
}
/// <summary>
/// Create a <see cref="MethodRef"/> from a <see cref="MethodDefinition"/>.
/// </summary>
public MethodRef(MethodDefinition methodDefinition, bool isFirstOnLine)
: base(methodDefinition, isFirstOnLine)
{ }
/// <summary>
/// Create a <see cref="MethodRef"/> from a <see cref="MethodDefinition"/>.
/// </summary>
public MethodRef(MethodDefinition methodDefinition)
: base(methodDefinition, false)
{ }
/// <summary>
/// Create a <see cref="MethodRef"/> from a <see cref="MethodDefinition"/>.
/// </summary>
public MethodRef(MethodDefinition methodDefinition, ChildList<Expression> typeArguments)
: this(methodDefinition, false, typeArguments)
{ }
/// <summary>
/// Create a <see cref="MethodRef"/> from a <see cref="MethodDefinition"/>.
/// </summary>
public MethodRef(MethodDefinition methodDefinition, bool isFirstOnLine, params Expression[] typeArguments)
: this(methodDefinition, isFirstOnLine, ((typeArguments != null && typeArguments.Length > 0) ? new ChildList<Expression>(typeArguments) : null))
{ }
/// <summary>
/// Create a <see cref="MethodRef"/> from a <see cref="MethodDefinition"/>.
/// </summary>
public MethodRef(MethodDefinition methodDefinition, params Expression[] typeArguments)
: this(methodDefinition, false, ((typeArguments != null && typeArguments.Length > 0) ? new ChildList<Expression>(typeArguments) : null))
{ }
/// <summary>
/// Create a <see cref="MethodRef"/> from a <see cref="MethodInfo"/>.
/// </summary>
public MethodRef(MethodInfo methodInfo, bool isFirstOnLine, ChildList<Expression> typeArguments)
: base(methodInfo, isFirstOnLine)
{
// If the method is generic, and no type arguments were specified, do NOT default any (they will be inferred).
// Unlike nested types, methods of generic types are not considered generic if they don't have any local type
// arguments, and generic methods never include type arguments of generic enclosing types (presumably, when
// assigned to a delegate, any type arguments of generic enclosing types will be included in the object reference
// associated with the delegate).
TypeArguments = typeArguments;
}
/// <summary>
/// Create a <see cref="MethodRef"/> from a <see cref="MethodInfo"/>.
/// </summary>
public MethodRef(MethodInfo methodInfo, bool isFirstOnLine)
: base(methodInfo, isFirstOnLine)
{ }
/// <summary>
/// Create a <see cref="MethodRef"/> from a <see cref="MethodInfo"/>.
/// </summary>
public MethodRef(MethodInfo methodInfo)
: base(methodInfo, false)
{ }
/// <summary>
/// Create a <see cref="MethodRef"/> from a <see cref="MethodInfo"/>.
/// </summary>
public MethodRef(MethodInfo methodInfo, ChildList<Expression> typeArguments)
: this(methodInfo, false, typeArguments)
{ }
/// <summary>
/// Create a <see cref="MethodRef"/> from a <see cref="MethodInfo"/>.
/// </summary>
public MethodRef(MethodInfo methodInfo, bool isFirstOnLine, params Expression[] typeArguments)
: this(methodInfo, isFirstOnLine, ((typeArguments != null && typeArguments.Length > 0) ? new ChildList<Expression>(typeArguments) : null))
{ }
/// <summary>
/// Create a <see cref="MethodRef"/> from a <see cref="MethodInfo"/>.
/// </summary>
public MethodRef(MethodInfo methodInfo, params Expression[] typeArguments)
: this(methodInfo, false, ((typeArguments != null && typeArguments.Length > 0) ? new ChildList<Expression>(typeArguments) : null))
{ }
protected MethodRef(AnonymousMethod anonymousMethod, bool isFirstOnLine)
: base(anonymousMethod, isFirstOnLine)
{ }
protected MethodRef(MethodBase methodBase, bool isFirstOnLine)
: base(methodBase, isFirstOnLine)
{
// Constructors of generic types are not generic methods, however the type arguments associated with their
// declaring type must be supplied when they are invoked - these are defaulted in ConstructorRef if omitted.
}
#endregion
#region /* PROPERTIES */
/// <summary>
/// The name of the <see cref="MethodRef"/>.
/// </summary>
public override string Name
{
get
{
if (_reference is INamedCodeObject)
return ((INamedCodeObject)_reference).Name;
if (_reference is MethodDefinition)
return ((MethodDefinition)_reference).Name;
if (_reference is MethodInfo)
return ((MethodInfo)_reference).Name;
return null;
}
}
/// <summary>
/// True if the referenced method is generic.
/// </summary>
public bool IsGenericMethod
{
get
{
if (_reference is MethodDeclBase)
return ((MethodDeclBase)_reference).IsGenericMethod;
if (_reference is MethodDefinition)
return ((MethodDefinition)_reference).HasGenericParameters;
if (_reference is MethodInfo)
return ((MethodInfo)_reference).IsGenericMethod;
return false;
}
}
/// <summary>
/// True if the referenced method has parameters.
/// </summary>
public bool HasParameters
{
get
{
if (_reference is MethodDeclBase)
return ((MethodDeclBase)_reference).HasParameters;
if (_reference is MethodDefinition)
return ((MethodDefinition)_reference).HasParameters;
if (_reference is MethodInfo)
return (((MethodInfo)_reference).GetParameters().Length > 0);
return false;
}
}
/// <summary>
/// The number of parameters the referenced method has.
/// </summary>
public int ParameterCount
{
get
{
if (_reference is MethodDeclBase)
return ((MethodDeclBase)_reference).ParameterCount;
if (_reference is MethodDefinition)
return ((MethodDefinition)_reference).Parameters.Count;
if (_reference is MethodInfo)
return ((MethodInfo)_reference).GetParameters().Length;
return 0;
}
}
/// <summary>
/// Get the parameters of the referenced method object (as either a <see cref="ChildList{ParameterDecl}"/> or a <see cref="ParameterInfo"/>[].
/// </summary>
public ICollection Parameters
{
get
{
if (_reference is MethodDeclBase)
return ((MethodDeclBase)_reference).Parameters;
if (_reference is MethodDefinition)
return ((MethodDefinition)_reference).Parameters;
if (_reference is MethodInfo)
return ((MethodInfo)_reference).GetParameters();
return null;
}
}
/// <summary>
/// True if the referenced method is abstract.
/// </summary>
public bool IsAbstract
{
get
{
if (_reference is MethodDeclBase)
return ((MethodDeclBase)_reference).IsAbstract;
if (_reference is MethodDefinition)
return ((MethodDefinition)_reference).IsAbstract;
if (_reference is MethodInfo)
return ((MethodInfo)_reference).IsAbstract;
return false;
}
}
/// <summary>
/// True if the referenced method is static.
/// </summary>
public override bool IsStatic
{
get
{
if (_reference is MethodDeclBase)
return ((MethodDeclBase)_reference).IsStatic;
if (_reference is MethodDefinition)
return ((MethodDefinition)_reference).IsStatic;
if (_reference is MethodInfo)
return ((MethodInfo)_reference).IsStatic;
return false;
}
}
/// <summary>
/// True if the referenced method has public access.
/// </summary>
public override bool IsPublic
{
get
{
if (HasArrayRanks) return GetElementType().IsPublic;
if (_reference is MethodDeclBase)
return ((MethodDeclBase)_reference).IsPublic;
if (_reference is MethodDefinition)
return ((MethodDefinition)_reference).IsPublic;
if (_reference is MethodInfo)
return ((MethodInfo)_reference).IsPublic;
return false;
}
}
/// <summary>
/// True if the referenced method has private access.
/// </summary>
public override bool IsPrivate
{
get
{
if (HasArrayRanks) return GetElementType().IsPrivate;
if (_reference is MethodDeclBase)
return ((MethodDeclBase)_reference).IsPrivate;
if (_reference is MethodDefinition)
return ((MethodDefinition)_reference).IsPrivate;
if (_reference is MethodInfo)
return ((MethodInfo)_reference).IsPrivate;
return false;
}
}
/// <summary>
/// True if the referenced method has protected access.
/// </summary>
public override bool IsProtected
{
get
{
if (HasArrayRanks) return GetElementType().IsProtected;
if (_reference is MethodDeclBase)
return ((MethodDeclBase)_reference).IsProtected;
if (_reference is MethodDefinition)
return ((MethodDefinition)_reference).IsFamily;
if (_reference is MethodInfo)
return ((MethodInfo)_reference).IsFamily;
return false;
}
}
/// <summary>
/// True if the referenced method has internal access.
/// </summary>
public override bool IsInternal
{
get
{
if (HasArrayRanks) return GetElementType().IsInternal;
if (_reference is MethodDeclBase)
return ((MethodDeclBase)_reference).IsInternal;
if (_reference is MethodDefinition)
return ((MethodDefinition)_reference).IsAssembly;
if (_reference is MethodInfo)
return ((MethodInfo)_reference).IsAssembly;
return false;
}
}
/// <summary>
/// True if the referenced method is virtual.
/// </summary>
public bool IsVirtual
{
get
{
if (_reference is MethodDeclBase)
return (((MethodDeclBase)_reference).IsVirtual || ((MethodDeclBase)_reference).IsOverride);
if (_reference is MethodDefinition)
return ((MethodDefinition)_reference).IsVirtual;
if (_reference is MethodInfo)
return ((MethodInfo)_reference).IsVirtual;
return false;
}
}
/// <summary>
/// True if the referenced method is an override.
/// </summary>
public bool IsOverride
{
get { return IsOverridden(_reference); }
}
/// <summary>
/// A <see cref="MethodRef"/> can't have array ranks, so this property always returns null, and throws
/// an exception if set to a non-null value.
/// </summary>
public override List<int> ArrayRanks
{
set
{
if (value != null)
throw new Exception("Can't set array ranks on a MethodRef!");
}
}
#endregion
#region /* STATIC METHODS */
/// <summary>
/// Construct a <see cref="MethodRef"/> or <see cref="ConstructorRef"/> from a <see cref="MethodReference"/>.
/// </summary>
public static MethodRef Create(MethodReference methodReference, bool isFirstOnLine, ChildList<Expression> typeArguments)
{
MethodDefinition methodDefinition = methodReference.Resolve();
return (methodDefinition.IsConstructor ? new ConstructorRef(methodDefinition, isFirstOnLine) : new MethodRef(methodDefinition, isFirstOnLine, typeArguments));
}
/// <summary>
/// Construct a <see cref="MethodRef"/> or <see cref="ConstructorRef"/> from a <see cref="MethodReference"/>.
/// </summary>
public static MethodRef Create(MethodReference methodReference, bool isFirstOnLine)
{
MethodDefinition methodDefinition = methodReference.Resolve();
return (methodDefinition.IsConstructor ? new ConstructorRef(methodDefinition, isFirstOnLine) : new MethodRef(methodDefinition, isFirstOnLine));
}
/// <summary>
/// Construct a <see cref="MethodRef"/> or <see cref="ConstructorRef"/> from a <see cref="MethodReference"/>.
/// </summary>
public static MethodRef Create(MethodReference methodReference)
{
MethodDefinition methodDefinition = methodReference.Resolve();
return (methodDefinition.IsConstructor ? new ConstructorRef(methodDefinition, false) : new MethodRef(methodDefinition, false));
}
/// <summary>
/// Construct a <see cref="MethodRef"/> or <see cref="ConstructorRef"/> from a <see cref="MethodReference"/>.
/// </summary>
public static MethodRef Create(MethodReference methodReference, ChildList<Expression> typeArguments)
{
MethodDefinition methodDefinition = methodReference.Resolve();
return (methodDefinition.IsConstructor ? new ConstructorRef(methodDefinition) : new MethodRef(methodDefinition, false, typeArguments));
}
/// <summary>
/// Construct a <see cref="MethodRef"/> or <see cref="ConstructorRef"/> from a <see cref="MethodReference"/>.
/// </summary>
public static MethodRef Create(MethodReference methodReference, bool isFirstOnLine, params Expression[] typeArguments)
{
MethodDefinition methodDefinition = methodReference.Resolve();
return (methodDefinition.IsConstructor ? new ConstructorRef(methodDefinition, isFirstOnLine) : new MethodRef(methodDefinition, isFirstOnLine, typeArguments));
}
/// <summary>
/// Construct a <see cref="MethodRef"/> or <see cref="ConstructorRef"/> from a <see cref="MethodReference"/>.
/// </summary>
public static MethodRef Create(MethodReference methodReference, params Expression[] typeArguments)
{
MethodDefinition methodDefinition = methodReference.Resolve();
return (methodDefinition.IsConstructor ? new ConstructorRef(methodDefinition) : new MethodRef(methodDefinition, false, typeArguments));
}
/// <summary>
/// Construct a <see cref="MethodRef"/> or <see cref="ConstructorRef"/> from a <see cref="MethodBase"/>.
/// </summary>
public static MethodRef Create(MethodBase methodBase, bool isFirstOnLine, ChildList<Expression> typeArguments)
{
if (methodBase != null)
return (methodBase is MethodInfo ? new MethodRef((MethodInfo)methodBase, isFirstOnLine, typeArguments) : new ConstructorRef((ConstructorInfo)methodBase, isFirstOnLine));
return null;
}
/// <summary>
/// Construct a <see cref="MethodRef"/> or <see cref="ConstructorRef"/> from a <see cref="MethodBase"/>.
/// </summary>
public static MethodRef Create(MethodBase methodBase, bool isFirstOnLine)
{
if (methodBase != null)
return (methodBase is MethodInfo ? new MethodRef((MethodInfo)methodBase, isFirstOnLine) : new ConstructorRef((ConstructorInfo)methodBase, isFirstOnLine));
return null;
}
/// <summary>
/// Construct a <see cref="MethodRef"/> or <see cref="ConstructorRef"/> from a <see cref="MethodBase"/>.
/// </summary>
public static MethodRef Create(MethodBase methodBase)
{
if (methodBase != null)
return (methodBase is MethodInfo ? new MethodRef((MethodInfo)methodBase, false) : new ConstructorRef((ConstructorInfo)methodBase, false));
return null;
}
/// <summary>
/// Construct a <see cref="MethodRef"/> or <see cref="ConstructorRef"/> from a <see cref="MethodBase"/>.
/// </summary>
public static MethodRef Create(MethodBase methodBase, ChildList<Expression> typeArguments)
{
if (methodBase != null)
return (methodBase is MethodInfo ? new MethodRef((MethodInfo)methodBase, false, typeArguments) : new ConstructorRef((ConstructorInfo)methodBase));
return null;
}
/// <summary>
/// Construct a <see cref="MethodRef"/> or <see cref="ConstructorRef"/> from a <see cref="MethodBase"/>.
/// </summary>
public static MethodRef Create(MethodBase methodBase, bool isFirstOnLine, params Expression[] typeArguments)
{
if (methodBase != null)
return (methodBase is MethodInfo ? new MethodRef((MethodInfo)methodBase, isFirstOnLine, typeArguments) : new ConstructorRef((ConstructorInfo)methodBase, isFirstOnLine));
return null;
}
/// <summary>
/// Construct a <see cref="MethodRef"/> or <see cref="ConstructorRef"/> from a <see cref="MethodBase"/>.
/// </summary>
public static MethodRef Create(MethodBase methodBase, params Expression[] typeArguments)
{
if (methodBase != null)
return (methodBase is MethodInfo ? new MethodRef((MethodInfo)methodBase, false, typeArguments) : new ConstructorRef((ConstructorInfo)methodBase));
return null;
}
/// <summary>
/// Find a method on the specified <see cref="TypeDecl"/> with the specified signature.
/// </summary>
/// <returns>A <see cref="MethodRef"/> to the method, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static TypeRefBase Find(TypeDecl typeDecl, string name, bool isFirstOnLine, params TypeRefBase[] parameterTypes)
{
if (typeDecl != null)
{
MethodRef methodRef = typeDecl.GetMethod(name, parameterTypes);
if (methodRef != null)
{
methodRef.IsFirstOnLine = isFirstOnLine;
return methodRef;
}
}
return new UnresolvedRef(name, isFirstOnLine, ResolveCategory.Method);
}
/// <summary>
/// Find a method on the specified <see cref="TypeDecl"/> with the specified signature.
/// </summary>
/// <returns>A <see cref="MethodRef"/> to the method, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static TypeRefBase Find(TypeDecl typeDecl, string name, params TypeRefBase[] parameterTypes)
{
return Find(typeDecl, name, false, parameterTypes);
}
/// <summary>
/// Find a method on the specified type <see cref="Alias"/> with the specified signature.
/// </summary>
/// <returns>A <see cref="MethodRef"/> to the method, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static TypeRefBase Find(Alias typeAlias, string name, bool isFirstOnLine, params TypeRefBase[] parameterTypes)
{
if (typeAlias != null)
{
MethodRef methodRef = typeAlias.GetMethod(name, parameterTypes);
if (methodRef != null)
{
methodRef.IsFirstOnLine = isFirstOnLine;
return methodRef;
}
}
return new UnresolvedRef(name, isFirstOnLine, ResolveCategory.Method);
}
/// <summary>
/// Find a method on the specified type <see cref="Alias"/> with the specified signature.
/// </summary>
/// <returns>A <see cref="MethodRef"/> to the method, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static TypeRefBase Find(Alias typeAlias, string name, params TypeRefBase[] parameterTypes)
{
return Find(typeAlias, name, false, parameterTypes);
}
/// <summary>
/// Find a method on the specified <see cref="Type"/> with the specified name and signature, using the specified <see cref="BindingFlags"/>.
/// </summary>
/// <returns>A <see cref="MethodRef"/> to the method, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static TypeRefBase Find(Type type, string name, BindingFlags bindingFlags, bool isFirstOnLine, params Type[] paramTypes)
{
if (type != null)
{
MethodInfo methodInfo = TypeUtil.GetMethod(type, name, bindingFlags, paramTypes);
if (methodInfo != null)
return new MethodRef(methodInfo, isFirstOnLine);
}
return new UnresolvedRef(name, isFirstOnLine, ResolveCategory.Method);
}
/// <summary>
/// Find a method on the specified <see cref="Type"/> with the specified name and signature.
/// </summary>
/// <returns>A <see cref="MethodRef"/> to the method, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static TypeRefBase Find(Type type, string name, bool isFirstOnLine, params Type[] paramTypes)
{
return Find(type, name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, isFirstOnLine, paramTypes);
}
/// <summary>
/// Find a method on the specified <see cref="Type"/> with the specified name and signature.
/// </summary>
/// <returns>A <see cref="MethodRef"/> to the method, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static TypeRefBase Find(Type type, string name, params Type[] paramTypes)
{
return Find(type, name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, false, paramTypes);
}
/// <summary>
/// Find a method on the specified <see cref="TypeRefBase"/> with the specified signature.
/// </summary>
/// <returns>A <see cref="MethodRef"/> to the method, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static TypeRefBase Find(TypeRefBase typeRefBase, string name, BindingFlags bindingFlags, bool isFirstOnLine, params TypeRefBase[] parameterTypes)
{
if (typeRefBase is TypeRef)
{
MethodRef methodRef = ((TypeRef)typeRefBase).GetMethod(name, bindingFlags, parameterTypes);
if (methodRef != null)
{
methodRef.IsFirstOnLine = isFirstOnLine;
return methodRef;
}
}
return new UnresolvedRef(name, isFirstOnLine, ResolveCategory.Method);
}
/// <summary>
/// Find a method on the specified <see cref="TypeRefBase"/> with the specified signature.
/// </summary>
/// <returns>A <see cref="MethodRef"/> to the method, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static TypeRefBase Find(TypeRefBase typeRefBase, string name, bool isFirstOnLine, params TypeRefBase[] parameterTypes)
{
return Find(typeRefBase, name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, isFirstOnLine, parameterTypes);
}
/// <summary>
/// Find a method on the specified <see cref="TypeRefBase"/> with the specified signature.
/// </summary>
/// <returns>A <see cref="MethodRef"/> to the method, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
public static TypeRefBase Find(TypeRefBase typeRefBase, string name, params TypeRefBase[] parameterTypes)
{
return Find(typeRefBase, name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, false, parameterTypes);
}
/// <summary>
/// Get any modifiers from the specified <see cref="MethodDefinition"/>.
/// </summary>
public static Modifiers GetMethodModifiers(MethodDefinition methodDefinition)
{
Modifiers modifiers = 0;
if (methodDefinition.IsPublic)
modifiers |= Modifiers.Public;
if (methodDefinition.IsFamily || methodDefinition.IsFamilyOrAssembly)
modifiers |= Modifiers.Protected;
if (methodDefinition.IsAssembly || methodDefinition.IsFamilyOrAssembly)
modifiers |= Modifiers.Internal;
if (methodDefinition.IsPrivate)
modifiers |= Modifiers.Private;
if (methodDefinition.IsAbstract)
modifiers |= Modifiers.Abstract;
if (methodDefinition.IsFinal)
modifiers |= Modifiers.Sealed;
if (methodDefinition.IsStatic)
modifiers |= Modifiers.Static;
if (methodDefinition.IsVirtual)
modifiers |= Modifiers.Virtual;
// If it's both 'virtual' and 'sealed', it's not relevant to external users, so
// hide them both (otherwise, various BCL methods will show these attributes).
if ((modifiers & (Modifiers.Virtual | Modifiers.Sealed)) == (Modifiers.Virtual | Modifiers.Sealed))
modifiers &= ~(Modifiers.Virtual | Modifiers.Sealed);
// 'override' would be nice instead of just 'virtual', but it's not really relevant to
// external users, and we'd have to scan base classes to determine the difference.
// 'new' isn't relevant to external users, so don't bother figuring it out (we could look
// at IsHideBySig, but we'd have to further determine if it's the hide-er or the hide-e).
// 'partial' and 'extern' aren't relevant to external users.
if (methodDefinition.IsSpecialName)
{
if (methodDefinition.Name == "op_Explicit")
modifiers |= Modifiers.Explicit;
else if (methodDefinition.Name == "op_Implicit")
modifiers |= Modifiers.Implicit;
}
return modifiers;
}
/// <summary>
/// Get any modifiers from the specified <see cref="MethodBase"/>.
/// </summary>
public static Modifiers GetMethodModifiers(MethodBase methodBase)
{
Modifiers modifiers = 0;
if (methodBase.IsPublic)
modifiers |= Modifiers.Public;
if (methodBase.IsFamily || methodBase.IsFamilyOrAssembly)
modifiers |= Modifiers.Protected;
if (methodBase.IsAssembly || methodBase.IsFamilyOrAssembly)
modifiers |= Modifiers.Internal;
if (methodBase.IsPrivate)
modifiers |= Modifiers.Private;
if (methodBase.IsAbstract)
modifiers |= Modifiers.Abstract;
if (methodBase.IsFinal)
modifiers |= Modifiers.Sealed;
if (methodBase.IsStatic)
modifiers |= Modifiers.Static;
if (methodBase.IsVirtual)
modifiers |= Modifiers.Virtual;
// If it's both 'virtual' and 'sealed', it's not relevant to external users, so
// hide them both (otherwise, various BCL methods will show these attributes).
if ((modifiers & (Modifiers.Virtual | Modifiers.Sealed)) == (Modifiers.Virtual | Modifiers.Sealed))
modifiers &= ~(Modifiers.Virtual | Modifiers.Sealed);
// 'override' would be nice instead of just 'virtual', but it's not really relevant to
// external users, and we'd have to scan base classes to determine the difference.
// 'new' isn't relevant to external users, so don't bother figuring it out (we could look
// at IsHideBySig, but we'd have to further determine if it's the hide-er or the hide-e).
// 'partial' and 'extern' aren't relevant to external users.
if (methodBase.IsSpecialName)
{
if (methodBase.Name == "op_Explicit")
modifiers |= Modifiers.Explicit;
else if (methodBase.Name == "op_Implicit")
modifiers |= Modifiers.Implicit;
}
return modifiers;
}
/// <summary>
/// Retrieve the parameters (if any) of a code object for a method, constructor, indexer, or delegate invocation.
/// </summary>
/// <param name="obj">The code object - can be an <see cref="IParameters"/> CodeObject (MethodDeclBase, IndexerDecl, DelegateDecl, AnonymousMethod),
/// MethodDefinition/MethodInfo, ConstructorInfo, or PropertyDefinition/PropertyInfo for an indexer; or an <see cref="IVariableDecl"/> CodeObject
/// (PropertyDeclBase, VariableDecl), FieldDefinition/FieldInfo, PropertyDefinition/PropertyInfo, or EventDefinition/EventInfo that has a delegate type).</param>
/// <param name="parentExpression">The parent expression of the code object.</param>
/// <returns>An <see cref="ICollection"/> of <see cref="ParameterDecl"/>s or <see cref="ParameterDefinition"/>/<see cref="ParameterInfo"/>s, or null if none were found.</returns>
public static ICollection GetParameters(object obj, Expression parentExpression)
{
// Handle method & indexer parameters
ICollection parameters = null;
if (obj is IParameters)
parameters = ((IParameters)obj).Parameters;
else if (obj is MethodDefinition) // Method or Constructor
return GetMethodParameters((MethodDefinition)obj);
else if (obj is PropertyDefinition && ((PropertyDefinition)obj).HasParameters)
return ((PropertyDefinition)obj).Parameters;
else if (obj is MethodBase) // MethodInfo or ConstructorInfo
return GetMethodParameters((MethodBase)obj);
else if (obj is PropertyInfo && PropertyInfoUtil.IsIndexed((PropertyInfo)obj))
return ((PropertyInfo)obj).GetIndexParameters();
else if (obj is IVariableDecl)
{
// Handle variables that evaluate to a delegate type
Expression type = ((IVariableDecl)obj).Type;
if (type != null)
{
// Evaluate if a TypeParameter
TypeRefBase typeRefBase = type.EvaluateType();
if (typeRefBase != null)
{
if (typeRefBase is TypeParameterRef)
typeRefBase = typeRefBase.EvaluateTypeArgumentTypes(parentExpression);
if (typeRefBase.IsDelegateType)
parameters = typeRefBase.GetDelegateParameters();
}
}
}
else if (obj is IMemberDefinition)
{
// Handle external variables that evaluate to a delegate type
TypeReference delegateType = null;
if (obj is FieldDefinition)
delegateType = ((FieldDefinition)obj).FieldType;
else if (obj is PropertyDefinition)
delegateType = ((PropertyDefinition)obj).PropertyType;
else if (obj is EventDefinition)
delegateType = ((EventDefinition)obj).EventType;
if (delegateType != null)
{
// Evaluate if a generic parameter
if (delegateType.IsGenericParameter)
parameters = TypeRef.Create(delegateType).EvaluateTypeArgumentTypes(parentExpression).GetDelegateParameters();
else
parameters = TypeDefinitionUtil.GetDelegateParameters(delegateType);
}
}
else //if (obj is MemberInfo)
{
// Handle external variables that evaluate to a delegate type
Type delegateType = null;
if (obj is FieldInfo)
delegateType = ((FieldInfo)obj).FieldType;
else if (obj is PropertyInfo)
delegateType = ((PropertyInfo)obj).PropertyType;
else if (obj is EventInfo)
delegateType = ((EventInfo)obj).EventHandlerType;
if (delegateType != null)
{
// Evaluate if a generic parameter
if (delegateType.IsGenericParameter)
parameters = TypeRef.Create(delegateType).EvaluateTypeArgumentTypes(parentExpression).GetDelegateParameters();
else
parameters = TypeUtil.GetDelegateParameters(delegateType);
}
}
return parameters;
}
/// <summary>
/// Retrieve the parameters (if any) of a code object for a method, constructor, indexer, or delegate invocation.
/// </summary>
/// <param name="obj">The code object - can be an <see cref="IParameters"/> CodeObject (MethodDeclBase, IndexerDecl, DelegateDecl, AnonymousMethod),
/// MethodDefinition/MethodInfo, ConstructorInfo, or PropertyDefinition/PropertyInfo for an indexer; or an <see cref="IVariableDecl"/> CodeObject
/// (PropertyDeclBase, VariableDecl), FieldDefinition/FieldInfo, PropertyDefinition/PropertyInfo, or EventDefinition/EventInfo that has a delegate type).</param>
/// <returns>An <see cref="ICollection"/> of <see cref="ParameterDecl"/>s or <see cref="ParameterDefinition"/>/<see cref="ParameterInfo"/>s, or null if none were found.</returns>
public static ICollection GetParameters(object obj)
{
return GetParameters(obj, null);
}
/// <summary>
/// Retrieve the type of the parameter with the specified index from the specified code object for a method, constructor, indexer, or delegate invocation.
/// </summary>
/// <param name="obj">The code object - can be an <see cref="IParameters"/> CodeObject (MethodDeclBase, IndexerDecl, DelegateDecl, AnonymousMethod),
/// MethodDefinition/MethodInfo, ConstructorInfo, or PropertyDefinition/PropertyInfo for an indexer; or an <see cref="IVariableDecl"/> CodeObject
/// (PropertyDeclBase, VariableDecl), FieldDefinition/FieldInfo, PropertyDefinition/PropertyInfo, or EventDefinition/EventInfo that has a delegate type).</param>
/// <param name="parameterIndex">The index of the parameter.</param>
/// <param name="parentExpression">The parent expression of the code object.</param>
/// <returns>The TypeRefBase representing the type of the parameter, otherwise null.</returns>
public static TypeRefBase GetParameterType(object obj, int parameterIndex, Expression parentExpression)
{
if (obj == null)
return null;
ICollection parameters = GetParameters(obj, parentExpression);
int parameterCount = (parameters != null ? parameters.Count : 0);
if (parameterCount == 0)
return null;
// Check for params parameter
bool isParamsParameter = false;
if (parameterIndex >= parameterCount - 1)
{
int paramsIndex = parameterCount - 1;
isParamsParameter = ParameterRef.ParameterIsParams(parameters, paramsIndex);
if (isParamsParameter)
parameterIndex = paramsIndex;
}
// Get the parameter type
TypeRefBase parameterType = null;
if (parameterIndex < parameterCount)
parameterType = ParameterRef.GetParameterType(parameters, parameterIndex, parentExpression) as TypeRef;
// Expand any params type - this routine wants the type of the parameter, so we shouldn't have to
// worry about a parameter that is an array of delegates (params del[]), since that wouldn't be a delegate.
if (isParamsParameter && parameterType != null)
parameterType = parameterType.GetElementType() as TypeRef;
return parameterType;
}
/// <summary>
/// Retrieve the type of the parameter with the specified index from the specified code object for a method, constructor, indexer, or delegate invocation.
/// </summary>
/// <param name="obj">The code object - can be an <see cref="IParameters"/> CodeObject (MethodDeclBase, IndexerDecl, DelegateDecl, AnonymousMethod),
/// MethodDefinition/MethodInfo, ConstructorInfo, or PropertyDefinition/PropertyInfo for an indexer; or an <see cref="IVariableDecl"/> CodeObject
/// (PropertyDeclBase, VariableDecl), FieldDefinition/FieldInfo, PropertyDefinition/PropertyInfo, or EventDefinition/EventInfo that has a delegate type).</param>
/// <param name="parameterIndex">The index of the parameter.</param>
/// <returns>The TypeRefBase representing the type of the parameter, otherwise null.</returns>
public static TypeRefBase GetParameterType(object obj, int parameterIndex)
{
return GetParameterType(obj, parameterIndex, null);
}
/// <summary>
/// Retrieve the return type of a code object for a method, constructor, indexer, or delegate invocation.
/// </summary>
/// <param name="obj">The code object - can be a MethodDeclBase, MethodDefinition/MethodInfo, or ConstructorInfo; an IndexerDecl,
/// or PropertyDefinition/PropertyInfo for an indexer; or an <see cref="IVariableDecl"/> CodeObject
/// (PropertyDeclBase, VariableDecl), FieldDefinition/FieldInfo, PropertyDefinition/PropertyInfo, or EventDefinition/EventInfo that has a delegate type).</param>
/// <param name="parentExpression">The parent expression of the code object.</param>
/// <returns>The <see cref="TypeRefBase"/> of the return type, or null if none exists.</returns>
public static TypeRefBase GetReturnType(object obj, Expression parentExpression)
{
// Handle method and indexer return types
TypeRefBase returnTypeRef = null;
if (obj is MethodDeclBase)
returnTypeRef = ((MethodDeclBase)obj).ReturnType.EvaluateType();
else if (obj is MethodDefinition)
{
MethodDefinition methodDefinition = (MethodDefinition)obj;
returnTypeRef = TypeRef.Create(methodDefinition.IsConstructor ? methodDefinition.DeclaringType : methodDefinition.ReturnType);
}
else if (obj is IndexerDecl)
returnTypeRef = ((IndexerDecl)obj).EvaluateType();
else if (obj is PropertyDefinition && ((PropertyDefinition)obj).HasParameters)
returnTypeRef = TypeRef.Create(((PropertyDefinition)obj).PropertyType);
else if (obj is MethodInfo)
returnTypeRef = TypeRef.Create(((MethodInfo)obj).ReturnType);
else if (obj is ConstructorInfo)
returnTypeRef = TypeRef.Create(((ConstructorInfo)obj).DeclaringType);
else if (obj is PropertyInfo && PropertyInfoUtil.IsIndexed((PropertyInfo)obj))
returnTypeRef = TypeRef.Create(((PropertyInfo)obj).PropertyType);
else if (obj is IVariableDecl)
{
// Handle variables that evaluate to a delegate type
Expression type = ((IVariableDecl)obj).Type;
if (type != null)
{
// Evaluate if a TypeParameter
TypeRefBase typeRefBase = type.EvaluateType();
if (typeRefBase != null)
{
if (typeRefBase is TypeParameterRef)
typeRefBase = typeRefBase.EvaluateTypeArgumentTypes(parentExpression);
if (typeRefBase.IsDelegateType)
returnTypeRef = typeRefBase.GetDelegateReturnType();
}
}
}
else if (obj is IMemberDefinition)
{
// Handle external variables that evaluate to a delegate type
TypeReference delegateType = null;
if (obj is FieldDefinition)
delegateType = ((FieldDefinition)obj).FieldType;
else if (obj is PropertyDefinition)
delegateType = ((PropertyDefinition)obj).PropertyType;
else if (obj is EventDefinition)
delegateType = ((EventDefinition)obj).EventType;
if (delegateType != null)
{
// Evaluate if a generic parameter
if (delegateType.IsGenericParameter)
returnTypeRef = TypeRef.Create(delegateType).EvaluateTypeArgumentTypes(parentExpression).GetDelegateReturnType();
else
returnTypeRef = TypeRef.Create(TypeDefinitionUtil.GetDelegateReturnType(delegateType));
}
}
else //if (obj is MemberInfo)
{
// Handle external variables that evaluate to a delegate type
Type delegateType = null;
if (obj is FieldInfo)
delegateType = ((FieldInfo)obj).FieldType;
else if (obj is PropertyInfo)
delegateType = ((PropertyInfo)obj).PropertyType;
else if (obj is EventInfo)
delegateType = ((EventInfo)obj).EventHandlerType;
if (delegateType != null)
{
// Evaluate if a generic parameter
if (delegateType.IsGenericParameter)
returnTypeRef = TypeRef.Create(delegateType).EvaluateTypeArgumentTypes(parentExpression).GetDelegateReturnType();
else
returnTypeRef = TypeRef.Create(TypeUtil.GetDelegateReturnType(delegateType));
}
}
return (returnTypeRef != null ? returnTypeRef.EvaluateTypeArgumentTypes(parentExpression) : null);
}
/// <summary>
/// Retrieve the return type of a code object for a method, constructor, indexer, or delegate invocation.
/// </summary>
/// <param name="obj">The code object - can be a MethodDeclBase, MethodDefinition/MethodInfo, or ConstructorInfo; an IndexerDecl,
/// or PropertyDefinition/PropertyInfo for an indexer; or an <see cref="IVariableDecl"/> CodeObject
/// (PropertyDeclBase, VariableDecl), FieldDefinition/FieldInfo, PropertyDefinition/PropertyInfo, or EventDefinition/EventInfo that has a delegate type).</param>
/// <returns>The <see cref="TypeRefBase"/> of the return type, or null if none exists.</returns>
public static TypeRefBase GetReturnType(object obj)
{
return GetReturnType(obj, null);
}
/// <summary>
/// Get the parameters of a MethodDefinition, handling the VarArgs calling convention.
/// </summary>
public static ICollection GetMethodParameters(MethodDefinition methodDefinition)
{
return methodDefinition.Parameters;
}
/// <summary>
/// Get the parameters of a MethodBase, handling the VarArgs calling convention.
/// </summary>
public static ICollection GetMethodParameters(MethodBase methodBase)
{
return methodBase.GetParameters();
}
/// <summary>
/// Get any constraints for the specified type parameter on the specified method, or on the base virtual method if the method is an override.
/// </summary>
public static List<TypeParameterConstraint> GetTypeParameterConstraints(MethodDefinition methodDefinition, GenericParameter typeParameter)
{
// Override methods don't specify constraints - they inherit them from the base virtual method.
// In order to handle invalid code, just look in the first occurrence of constraints, searching
// any base method if the current one is an override.
List<TypeParameterConstraint> constraints = TypeParameterConstraint.Create(typeParameter);
if (constraints == null || constraints.Count == 0)
{
MethodDefinition baseMethodInfo = MethodDefinitionUtil.FindBaseMethod(methodDefinition);
if (baseMethodInfo != null)
{
// If the constraints are from a base method, we have to translate the type parameter
int index = MethodDefinitionUtil.FindTypeParameterIndex(methodDefinition, typeParameter);
typeParameter = MethodDefinitionUtil.GetTypeParameter(baseMethodInfo, index);
constraints = GetTypeParameterConstraints(baseMethodInfo, typeParameter);
}
}
return constraints;
}
/// <summary>
/// Get any constraints for the specified type parameter on the specified method, or on the base virtual method if the method is an override.
/// </summary>
public static List<TypeParameterConstraint> GetTypeParameterConstraints(MethodInfo methodInfo, Type typeParameter)
{
// Override methods don't specify constraints - they inherit them from the base virtual method.
// In order to handle invalid code, just look in the first occurrence of constraints, searching
// any base method if the current one is an override.
List<TypeParameterConstraint> constraints = TypeParameterConstraint.Create(typeParameter);
if (constraints == null || constraints.Count == 0)
{
MethodInfo baseMethodInfo = MethodInfoUtil.FindBaseMethod(methodInfo);
if (baseMethodInfo != null)
{
// If the constraints are from a base method, we have to translate the type parameter
int index = MethodInfoUtil.FindTypeParameterIndex(methodInfo, typeParameter);
typeParameter = MethodInfoUtil.GetTypeParameter(baseMethodInfo, index);
constraints = GetTypeParameterConstraints(baseMethodInfo, typeParameter);
}
}
return constraints;
}
/// <summary>
/// Determine the delegate type of the parameter of the specified method object with the specified argument index.
/// </summary>
/// <param name="obj">The code object (an IParameters CodeObject, MethodInfo, ConstructorInfo, or PropertyInfo for an indexer;
/// or an IVariableDecl CodeObject, FieldInfo, PropertyInfo, or EventInfo that has a delegate type).</param>
/// <param name="parameterIndex">The index of the parameter.</param>
/// <param name="parentExpression">The parent expression of the code object.</param>
/// <returns>The TypeRefBase representing the delegate type of the parameter, otherwise null.</returns>
public static TypeRefBase GetDelegateParameterType(object obj, int parameterIndex, Expression parentExpression)
{
// Get the parameter type
TypeRefBase delegateType = GetParameterType(obj, parameterIndex, parentExpression);
// Return null if the type isn't a delegate type
if (delegateType != null && !delegateType.IsDelegateType)
delegateType = null;
return delegateType;
}
/// <summary>
/// True if the specified method object is an override.
/// </summary>
public static bool IsOverridden(object method)
{
if (method is MethodDeclBase)
return ((MethodDeclBase)method).IsOverride;
if (method is MethodDefinition)
return MethodDefinitionUtil.IsOverride((MethodDefinition)method);
if (method is MethodInfo)
return MethodInfoUtil.IsOverride((MethodInfo)method);
return false;
}
/// <summary>
/// Get a list of MethodRefs from the specified NamedCodeObjectGroup.
/// </summary>
public static List<MethodRef> MethodRefsFromGroup(NamedCodeObjectGroup namedCodeObjectGroup)
{
List<MethodRef> methods = null;
if (namedCodeObjectGroup.Count > 0)
{
methods = new List<MethodRef>();
foreach (object methodObj in namedCodeObjectGroup)
{
MethodRef methodRef;
if (methodObj is MethodDeclBase)
methodRef = (MethodRef)((MethodDeclBase)methodObj).CreateRef();
else if (methodObj is MethodDefinition)
methodRef = Create((MethodDefinition)methodObj);
else
methodRef = Create((MethodBase)methodObj);
methods.Add(methodRef);
}
}
return methods;
}
#endregion
#region /* METHODS */
/// <summary>
/// Get the return type of the method (never null - will be type 'void' instead).
/// </summary>
public virtual TypeRefBase GetReturnType()
{
TypeRefBase returnTypeRef = null;
if (_reference is MethodDeclBase)
returnTypeRef = ((MethodDeclBase)_reference).ReturnType.EvaluateType();
else if (_reference is MethodDefinition)
{
MethodDefinition methodDefinition = (MethodDefinition)_reference;
TypeReference returnType = methodDefinition.ReturnType;
returnTypeRef = TypeRef.Create(returnType);
}
else if (_reference is MethodInfo)
{
MethodInfo methodInfo = (MethodInfo)_reference;
Type returnType = methodInfo.ReturnType;
returnTypeRef = TypeRef.Create(returnType);
}
// Evaluate the return type in order to replace any type parameters with type arguments
if (returnTypeRef != null)
returnTypeRef = returnTypeRef.EvaluateTypeArgumentTypes(this);
return returnTypeRef;
}
/// <summary>
/// Get the declaring type of the referenced method.
/// </summary>
public override TypeRefBase GetDeclaringType()
{
TypeRefBase declaringTypeRef = GetDeclaringType(_reference);
// A method reference doesn't store any type arguments for a parent type instance, so any
// type arguments in any generic declaring type or its parent types will always default to
// the declared type arguments. Convert them from OpenTypeParameterRefs to TypeParameterRefs
// so that they don't show up as Red in the GUI.
if (declaringTypeRef != null && declaringTypeRef.HasTypeArguments)
declaringTypeRef.ConvertOpenTypeParameters();
return declaringTypeRef;
}
/// <summary>
/// Get the declaring type of the specified method object.
/// </summary>
/// <param name="methodObj">The method object (a <see cref="MethodDeclBase"/> or <see cref="MethodDefinition"/>/<see cref="MethodBase"/>).</param>
/// <returns>The <see cref="TypeRef"/> of the declaring type, or null if it can't be determined.</returns>
public static TypeRefBase GetDeclaringType(object methodObj)
{
TypeRefBase declaringTypeRef = null;
if (methodObj is MethodDeclBase)
{
TypeDecl declaringTypeDecl = ((MethodDeclBase)methodObj).DeclaringType;
declaringTypeRef = (declaringTypeDecl != null ? declaringTypeDecl.CreateRef() : null);
}
else if (methodObj is MethodDefinition)
declaringTypeRef = TypeRef.Create(((MethodDefinition)methodObj).DeclaringType);
else if (methodObj is MethodBase)
declaringTypeRef = TypeRef.Create(((MethodBase)methodObj).DeclaringType);
return declaringTypeRef;
}
/// <summary>
/// Always returns <c>null</c>.
/// </summary>
public override TypeRefBase GetElementType()
{
return null;
}
/// <summary>
/// Find the parameter with the specified name.
/// </summary>
public ParameterRef GetParameter(string name)
{
object reference = GetReferencedType();
if (reference is MethodDeclBase)
return ((MethodDeclBase)reference).GetParameter(name);
if (reference is MethodDefinition)
{
ParameterDefinition parameterDefinition = MethodDefinitionUtil.GetParameter((MethodDefinition)reference, name);
if (parameterDefinition != null)
return new ParameterRef(parameterDefinition);
}
if (reference is MethodBase)
{
ParameterInfo parameterInfo = MethodInfoUtil.GetParameter((MethodBase)reference, name);
if (parameterInfo != null)
return new ParameterRef(parameterInfo);
}
return null;
}
/// <summary>
/// Get the type of the parameter with the specified index.
/// </summary>
/// <param name="parameterIndex">The index of the parameter.</param>
/// <param name="parentExpression">The parent expression for type evaluation purposes.</param>
/// <returns>The TypeRefBase representing the type of the parameter, otherwise null.</returns>
public TypeRefBase GetParameterType(int parameterIndex, Expression parentExpression)
{
return GetParameterType(Reference, parameterIndex, parentExpression);
}
/// <summary>
/// Get the type of the parameter with the specified index.
/// </summary>
/// <param name="parameterIndex">The index of the parameter.</param>
/// <returns>The TypeRefBase representing the type of the parameter, otherwise null.</returns>
public TypeRefBase GetParameterType(int parameterIndex)
{
return GetParameterType(Reference, parameterIndex, null);
}
/// <summary>
/// Get the type parameter of the referenced method declaration with the specified index (returns null if not found).
/// </summary>
public TypeParameterRef GetTypeParameter(int index)
{
if (_reference is GenericMethodDecl)
{
TypeParameter typeParameter = ((GenericMethodDecl)_reference).GetTypeParameter(index);
if (typeParameter != null)
return (TypeParameterRef)typeParameter.CreateRef();
}
else if (_reference is MethodDefinition)
{
GenericParameter genericParameter = MethodDefinitionUtil.GetTypeParameter((MethodDefinition)_reference, index);
if (genericParameter != null)
return new TypeParameterRef(genericParameter);
}
else if (_reference is MethodInfo)
{
Type typeParameter = MethodInfoUtil.GetTypeParameter((MethodInfo)_reference, index);
if (typeParameter != null)
return new TypeParameterRef(typeParameter);
}
return null;
}
/// <summary>
/// Get any constraints for the specified type parameter on this method, or on the base virtual method if this method is an override.
/// </summary>
public List<TypeParameterConstraint> GetTypeParameterConstraints(TypeParameterRef typeParameterRef)
{
if (_reference is GenericMethodDecl)
return ((GenericMethodDecl)_reference).GetTypeParameterConstraints(typeParameterRef.Reference as TypeParameter);
if (_reference is MethodDefinition)
return GetTypeParameterConstraints((MethodDefinition)_reference, typeParameterRef.Reference as GenericParameter);
if (_reference is MethodInfo)
return GetTypeParameterConstraints((MethodInfo)_reference, typeParameterRef.Reference as Type);
return null;
}
/// <summary>
/// Get the delegate parameters if the expression evaluates to a delegate type.
/// </summary>
public override ICollection GetDelegateParameters()
{
return Parameters;
}
/// <summary>
/// Get the delegate return type if the expression evaluates to a delegate type.
/// </summary>
public override TypeRefBase GetDelegateReturnType()
{
return GetReturnType();
}
/// <summary>
/// Invalid for a <see cref="MethodRef"/> - throws an exception if called.
/// </summary>
public override List<int> CreateArrayRanks()
{
throw new Exception("Can't create array ranks on a MethodRef!");
}
/// <summary>
/// Always returns the current <see cref="MethodRef"/> object, because it doesn't make sense to add array ranks to a MethodRef.
/// </summary>
public override TypeRefBase MakeArrayRef(List<int> ranksToBeCopied)
{
return this;
}
/// <summary>
/// Get the full name of the object, including the namespace name.
/// </summary>
public override string GetFullName()
{
object reference = GetReferencedType();
if (reference is MethodDeclBase)
return ((MethodDeclBase)reference).GetFullName();
if (reference is MethodDefinition)
return MemberReferenceUtil.GetFullName((MethodDefinition)reference);
if (reference is MethodBase)
return MemberInfoUtil.GetFullName((MethodBase)reference);
return null;
}
#endregion
#region /* PARSING */
/// <summary>
/// Does nothing, because it makes no sense to parse array ranks on a <see cref="MethodRef"/>.
/// </summary>
public override void ParseArrayRanks(Parser parser)
{ }
#endregion
#region /* RESOLVING */
/// <summary>
/// Resolve all child symbolic references, using the specified <see cref="ResolveCategory"/> and <see cref="ResolveFlags"/>.
/// </summary>
public override CodeObject Resolve(ResolveCategory resolveCategory, ResolveFlags flags)
{
// If we have inferred type arguments, we must re-resolve every time this method is called in
// case the type arguments infer differently. For example, an unresolved type in the parent
// tree could result in a type of 'IEnumerable<object>' that results in an inferred type argument
// of 'object', while at a later time it might infer as a more specific type.
// Also, for inferred type arguments, we don't want to copy or resolve the type arguments.
if (HasInferredTypeArguments)
{
UnresolvedRef unresolvedRef = new UnresolvedRef(this, resolveCategory, false);
// We have to fixup the parent pointer to this object before resolving in order for
// the resolution logic to work properly.
if (_parent is BinaryOperator)
{
if (((BinaryOperator)_parent).Right == this)
((BinaryOperator)_parent).Right = unresolvedRef;
else if (((BinaryOperator)_parent).Left == this)
((BinaryOperator)_parent).Left = unresolvedRef;
}
return unresolvedRef.Resolve(resolveCategory, flags);
}
return base.Resolve(resolveCategory, flags);
}
/// <summary>
/// Evaluate the type of the <see cref="Expression"/>.
/// </summary>
/// <returns>The resulting <see cref="TypeRef"/> or <see cref="UnresolvedRef"/>.</returns>
public override TypeRefBase EvaluateType(bool withoutConstants)
{
// A MethodRef evaluates to itself (it's a TypeRefBase, and can be treated as a delegate-like type)
return this;
}
/// <summary>
/// Find a type argument for the specified type parameter.
/// </summary>
public override TypeRefBase FindTypeArgument(TypeParameterRef typeParameterRef, CodeObject originatingChild)
{
if (HasTypeArguments)
{
int index = -1;
if (_reference is GenericMethodDecl)
index = ((GenericMethodDecl)_reference).FindTypeParameterIndex(typeParameterRef.Reference as TypeParameter);
else if (_reference is MethodDefinition)
index = MethodDefinitionUtil.FindTypeParameterIndex((MethodDefinition)_reference, typeParameterRef.Reference as GenericParameter);
else if (_reference is MethodInfo)
index = MethodInfoUtil.FindTypeParameterIndex((MethodInfo)_reference, typeParameterRef.Reference as Type);
if (index >= 0 && index < TypeArgumentCount)
{
Expression typeArgument = TypeArguments[index];
if (typeArgument != null)
return typeArgument.EvaluateType();
}
// If we didn't find a match, also recursively search any nested type arguments, but NOT if they are inferred
if (!HasInferredTypeArguments)
return FindNestedTypeArgument(typeParameterRef);
}
return null;
}
/// <summary>
/// Determine if the MethodRef is implicitly convertible to the specified TypeRefBase.
/// </summary>
/// <param name="toTypeRefBase">The TypeRef, MethodRef, or UnresolvedRef being checked.</param>
/// <param name="standardConversionsOnly">True if only standard conversions should be allowed.</param>
public override bool IsImplicitlyConvertibleTo(TypeRefBase toTypeRefBase, bool standardConversionsOnly)
{
// MethodRefs are only convertible to resolved delegate types
TypeRef toTypeRef = toTypeRefBase as TypeRef;
if (toTypeRef == null)
return false;
if (!toTypeRef.IsDelegateType)
{
// Except, also allow conversion to delegate base types as in TypeRef.ImplicitReferenceConversionExists()
// (this is done specifically so that evaluation of user-defined operators that work on delegates will work)
// - From any delegate-type to System.MulticastDelegate or System.Delegate, or the interfaces they implement
return (toTypeRef.IsSameRef(TypeRef.MulticastDelegateRef) || toTypeRef.IsSameRef(TypeRef.DelegateRef)
|| toTypeRef.IsSameRef(TypeRef.ICloneableRef) || toTypeRef.IsSameRef(TypeRef.ISerializableRef));
}
// Allow the conversion if the method parameter types and return value are compatible with those of the
// delegate type. Matching the expanded form of a 'params' parameter is NOT allowed.
// Get the return type and method parameters
TypeRefBase returnTypeRef;
ICollection methodParameters;
if (_reference is ConstructorDecl)
{
ConstructorDecl constructorDecl = (ConstructorDecl)_reference;
returnTypeRef = constructorDecl.GetDeclaringType();
if (returnTypeRef == null)
return false;
methodParameters = constructorDecl.Parameters;
}
else if (_reference is MethodDeclBase)
{
MethodDeclBase methodDeclBase = (MethodDeclBase)_reference;
returnTypeRef = methodDeclBase.ReturnType.EvaluateType();
// We must set the originating child for proper evaluation if the method's declaring type is generic
CodeObject originatingChild = (_parent is Dot ? ((Dot)_parent).Right : null);
returnTypeRef = returnTypeRef.EvaluateTypeArgumentTypes(this, originatingChild);
methodParameters = methodDeclBase.Parameters;
}
else if (_reference is MethodDefinition)
{
MethodDefinition methodDefinition = (MethodDefinition)_reference;
if (methodDefinition.IsConstructor)
{
returnTypeRef = TypeRef.Create(methodDefinition.DeclaringType);
methodParameters = methodDefinition.Parameters;
}
else
{
returnTypeRef = TypeRef.Create(methodDefinition.ReturnType);
// We must set the originating child for proper evaluation if the method's declaring type is generic
CodeObject originatingChild = (_parent is Dot ? ((Dot)_parent).Right : null);
returnTypeRef = returnTypeRef.EvaluateTypeArgumentTypes(this, originatingChild);
methodParameters = methodDefinition.Parameters;
}
}
else if (_reference is ConstructorInfo)
{
ConstructorInfo constructorInfo = (ConstructorInfo)_reference;
returnTypeRef = TypeRef.Create(constructorInfo.DeclaringType);
methodParameters = constructorInfo.GetParameters();
}
else if (_reference is MethodInfo)
{
MethodInfo methodInfo = (MethodInfo)_reference;
returnTypeRef = TypeRef.Create(methodInfo.ReturnType);
// We must set the originating child for proper evaluation if the method's declaring type is generic
CodeObject originatingChild = (_parent is Dot ? ((Dot)_parent).Right : null);
returnTypeRef = returnTypeRef.EvaluateTypeArgumentTypes(this, originatingChild);
methodParameters = methodInfo.GetParameters();
}
else
return false;
// Check if the return types are compatible
if (!returnTypeRef.IsImplicitlyConvertibleTo(toTypeRef.GetDelegateReturnType()))
return false;
// Get the delegate parameters
ICollection delegateParameters = toTypeRef.GetDelegateParameters();
int delegateParameterCount = (delegateParameters != null ? delegateParameters.Count : 0);
// The parameter counts must match ('params' are NOT expanded in this situation)
if ((methodParameters != null ? methodParameters.Count : 0) != delegateParameterCount)
return false;
// For each delegate parameter, check if its type is compatible with the method parameter
TypeRefBase paramsTypeRef = null;
for (int i = 0; i < delegateParameterCount; ++i)
{
// Get the type of the delegate parameter
TypeRefBase delegateParameterRef = ParameterRef.GetParameterType(delegateParameters, i, toTypeRef);
// Check if the parameter types match, passing 'this' as the parent expression in case it contains type arguments
// that can be used to evaluate any parameters with a type parameter type.
bool failedBecauseUnresolved;
if (!ParameterRef.MatchParameter(this, toTypeRef.Reference, null, methodParameters, i,
delegateParameterCount, delegateParameterRef, ref paramsTypeRef, false, this, out failedBecauseUnresolved))
return false;
}
return true;
}
#endregion
#region /* RENDERING */
public override void AsTextExpression(CodeWriter writer, RenderFlags flags)
{
// If we have no dot prefix, and the ShowParentTypes flag is set, then render all parent types
// (this shouldn't occur in display of code, but only when displaying an evaluated type reference,
// such as in a tooltip). Generic methods won't include type arguments for enclosing types, so
// we don't have to worry about them.
if (!flags.HasFlag(RenderFlags.HasDotPrefix) && flags.HasFlag(RenderFlags.ShowParentTypes))
{
TypeRefBase typeRef = GetDeclaringType();
if (typeRef != null)
{
typeRef.AsText(writer, flags);
writer.Write(Dot.ParseToken);
flags |= RenderFlags.HasDotPrefix;
}
}
else
UpdateLineCol(writer, flags);
if (_reference is MethodDeclBase)
writer.WriteIdentifier(((MethodDeclBase)_reference).Name, flags);
else if (_reference is MethodDefinition)
writer.WriteIdentifier(((MethodDefinition)_reference).Name, flags);
else if (_reference is MethodInfo)
writer.WriteIdentifier(((MethodInfo)_reference).Name, flags);
if (!HasInferredTypeArguments || flags.HasFlag(RenderFlags.Description))
AsTextTypeArguments(writer, _typeArguments, flags);
}
public static void AsTextMethodDefinition(CodeWriter writer, MethodDefinition methodDefinition, RenderFlags flags)
{
RenderFlags passFlags = flags & ~RenderFlags.Description;
if (!flags.HasFlag(RenderFlags.NoPreAnnotations))
{
Attribute.AsTextAttributes(writer, methodDefinition);
Attribute.AsTextAttributes(writer, methodDefinition.MethodReturnType, AttributeTarget.Return);
}
Modifiers modifiers = GetMethodModifiers(methodDefinition);
writer.Write(ModifiersHelpers.AsString(modifiers));
bool isConversionOperator = (modifiers.HasFlag(Modifiers.Explicit) || modifiers.HasFlag(Modifiers.Implicit));
if (!methodDefinition.IsConstructor && !isConversionOperator)
{
TypeReference returnType = methodDefinition.ReturnType;
AsTextTypeReference(writer, returnType, passFlags);
writer.Write(" ");
}
TypeReference declaringType = methodDefinition.DeclaringType;
AsTextTypeReference(writer, declaringType, passFlags);
Dot.AsTextDot(writer);
if (methodDefinition.IsConstructor)
writer.WriteName(declaringType.HasGenericParameters ? TypeDefinitionUtil.NonGenericName(declaringType) : declaringType.Name, passFlags);
else if (methodDefinition.HasGenericParameters)
AsTextGenericMember(writer, methodDefinition.Name, (IEnumerable<TypeReference>)methodDefinition.GenericParameters, passFlags);
else if (methodDefinition.Name.StartsWith(Operator.NamePrefix))
{
// Convert the internal name into the appropriate symbol
writer.Write(OperatorDecl.ParseToken + " ");
if (isConversionOperator)
AsTextTypeReference(writer, methodDefinition.ReturnType, passFlags);
else
writer.Write(OperatorDecl.GetOperatorSymbol(methodDefinition.Name));
}
else
writer.Write(methodDefinition.Name);
AsTextMethodParameters(writer, methodDefinition, passFlags);
// Render type constraints (if any)
if (methodDefinition.HasGenericParameters)
AsTextConstraints(writer, methodDefinition.GenericParameters);
}
public static void AsTextMethodParameters(CodeWriter writer, MethodDefinition methodDefinition, RenderFlags flags)
{
writer.Write(MethodDeclBase.ParseTokenStart);
ICollection parameters = GetMethodParameters(methodDefinition);
if (parameters is ChildList<ParameterDecl>)
writer.WriteList((ChildList<ParameterDecl>)parameters, flags, null);
else if (parameters is Collection<ParameterDefinition>)
AsTextParameters(writer, (Collection<ParameterDefinition>)parameters, flags);
else //if (parameters is ParameterInfo[])
AsTextParameters(writer, (ParameterInfo[])parameters, flags);
writer.Write(MethodDeclBase.ParseTokenEnd);
}
public static void AsTextParameters(CodeWriter writer, Collection<ParameterDefinition> parameters, RenderFlags flags)
{
for (int i = 0; i < parameters.Count; ++i)
{
ParameterDefinition parameterDefinition = parameters[i];
if (i > 0)
writer.Write(ParameterDecl.ParseTokenSeparator + " ");
ParameterRef.AsTextParameterDefinition(writer, parameterDefinition, flags);
}
}
public static void AsTextMethodInfo(CodeWriter writer, MethodInfo methodInfo, RenderFlags flags)
{
RenderFlags passFlags = flags & ~RenderFlags.Description;
if (!flags.HasFlag(RenderFlags.NoPreAnnotations))
{
Attribute.AsTextAttributes(writer, methodInfo);
Attribute.AsTextAttributes(writer, methodInfo.ReturnParameter, AttributeTarget.Return);
}
Modifiers modifiers = GetMethodModifiers(methodInfo);
writer.Write(ModifiersHelpers.AsString(modifiers));
bool isConversionOperator = (modifiers.HasFlag(Modifiers.Explicit) || modifiers.HasFlag(Modifiers.Implicit));
if (!isConversionOperator)
{
Type returnType = methodInfo.ReturnType;
AsTextType(writer, returnType, passFlags);
writer.Write(" ");
}
Type declaringType = methodInfo.DeclaringType;
AsTextType(writer, declaringType, passFlags);
Dot.AsTextDot(writer);
if (methodInfo.IsGenericMethod)
AsTextGenericMember(writer, methodInfo.Name, methodInfo.GetGenericArguments(), passFlags);
else if (methodInfo.Name.StartsWith(Operator.NamePrefix))
{
// Convert the internal name into the appropriate symbol
writer.Write(OperatorDecl.ParseToken + " ");
if (isConversionOperator)
AsTextType(writer, methodInfo.ReturnType, passFlags);
else
writer.Write(OperatorDecl.GetOperatorSymbol(methodInfo.Name));
}
else
writer.Write(methodInfo.Name);
AsTextMethodParameters(writer, methodInfo, passFlags);
// Render type constraints (if any)
if (methodInfo.IsGenericMethod)
AsTextConstraints(writer, methodInfo.GetGenericMethodDefinition().GetGenericArguments());
}
public static void AsTextMethodParameters(CodeWriter writer, MethodBase methodBase, RenderFlags flags)
{
writer.Write(MethodDeclBase.ParseTokenStart);
ICollection parameters = GetMethodParameters(methodBase);
if (parameters is ParameterInfo[])
AsTextParameters(writer, (ParameterInfo[])parameters, flags);
else
writer.WriteList((ChildList<ParameterDecl>)parameters, flags, null);
writer.Write(MethodDeclBase.ParseTokenEnd);
}
public static void AsTextParameters(CodeWriter writer, ParameterInfo[] parameters, RenderFlags flags)
{
for (int i = 0; i < parameters.Length; ++i)
{
ParameterInfo parameterInfo = parameters[i];
if (i > 0)
writer.Write(ParameterDecl.ParseTokenSeparator + " ");
ParameterRef.AsTextParameterInfo(writer, parameterInfo, flags);
}
}
#endregion
}
}