Click here to Skip to main content
15,880,854 members
Articles / Programming Languages / C#

Resolving Symbolic References in a CodeDOM (Part 7)

Rate me:
Please Sign up or sign in to vote.
4.75/5 (6 votes)
2 Dec 2012CDDL12 min read 19.4K   509   14  
Resolving symbolic references in a CodeDOM.
// 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
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)


Written By
Software Developer (Senior)
United States United States
I've been writing software since the late 70's, currently focusing mainly on C#.NET. I also like to travel around the world, and I own a Chocolate Factory (sadly, none of my employees are oompa loompas).

Comments and Discussions