Click here to Skip to main content
15,881,715 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.Linq;
using System.Reflection;
using System.Runtime.Serialization;
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 an <see cref="ITypeDecl"/> (<see cref="TypeDecl"/>, <see cref="TypeParameter"/>,
    /// <see cref="Alias"/>) or an external <see cref="TypeDefinition"/>/<see cref="Type"/>.
    /// </summary>
    /// <remarks>
    /// A TypeRef will reference an ITypeDecl code object for types defined in the same solution, otherwise
    /// it will directly reference a <see cref="TypeDefinition"/> or <see cref="GenericParameter"/> (if using
    /// Mono Cecil) or <see cref="Type"/> (if using reflection) object.  An ITypeDecl might be a TypeDecl, a
    /// TypeParameter (using the TypeParameterRef derived class), an Alias to a type (using the AliasRef derived
    /// class), an Anonymous Type (using the AnonymousTypeRef derived class), or a Var Type (using the VarTypeRef
    /// derived class).  When referencing TypeDecls or TypeDefinitions/GenericParameters, any array ranks and/or
    /// type arguments are part of the TypeRef itself.  When referencing Types, array and generic instance Types
    /// can be directly referenced.  In the hybrid case of a generic Type with one or more TypeDecls as type
    /// parameters, the TypeRef will reference the generic Type with empty type arguments, with the actual type
    /// parameters stored in the TypeRef.
    /// 
    /// If the TypeRef is actually a VarTypeRef, then the _reference member will be null, and the Reference
    /// property must be used to get the reference.  In this case, the Reference can be a string if the type
    /// of the VarTypeRef's type is an UnresolvedRef.
    /// 
    /// A TypeRef may also reference a constant, which has both a type and a value.  Most constants are of
    /// built-in types, and the reference will be to the 'int' or 'string' object, etc.  For enums, the
    /// reference will be to an EnumConstant object, which stores a TypeRef to the enum type plus an object
    /// of the underlying type of the enum containing the value of the constant.  For 'null' constants, the
    /// reference will be to the ITypeDecl or Type as normal, with a flag set to indicate the 'null' constant.
    /// </remarks>
    public class TypeRef : TypeRefBase
    {
        #region /* STATICS */

        /// <summary>
        /// A hash set of primitive type names (the "System" namespace prefix is NOT included on the names).
        /// </summary>
        public static readonly HashSet<string> PrimitiveTypeNames = new HashSet<string>
            {
                "SByte",
                "Byte",
                "Int16",
                "UInt16",
                "Int32",
                "UInt32",
                "Int64",
                "UInt64",
                "IntPtr",
                "UIntPtr",
                "Char",
                "Boolean",
                "Single",
                "Double"
            };

        /// <summary>
        /// A map of type names to TypeCodes (the "System" namespace prefix is NOT included on the names).
        /// </summary>
        public static readonly Dictionary<string, TypeCode> TypeNameToTypeCodeMap = new Dictionary<string, TypeCode>(17)
            {
                { "Object",   TypeCode.Object   },
                { "SByte",    TypeCode.SByte    },
                { "Byte",     TypeCode.Byte     },
                { "Int16",    TypeCode.Int16    },
                { "UInt16",   TypeCode.UInt16   },
                { "Int32",    TypeCode.Int32    },
                { "UInt32",   TypeCode.UInt32   },
                { "Int64",    TypeCode.Int64    },
                { "UInt64",   TypeCode.UInt64   },
                { "Char",     TypeCode.Char     },
                { "Boolean",  TypeCode.Boolean  },
                { "String",   TypeCode.String   },
                { "Single",   TypeCode.Single   },
                { "Double",   TypeCode.Double   },
                { "Decimal",  TypeCode.Decimal  },
                { "DateTime", TypeCode.DateTime },
                { "DBNull",   TypeCode.DBNull   }
            };

        /// <summary>
        /// A map of type names to primitive and built-in .NET types.
        /// </summary>
        public static readonly Dictionary<string, Type> TypeNameToTypeMap = new Dictionary<string, Type>(16)
            {
                { "System.Object",  typeof(object)  },
                { "System.Void",    typeof(void)    },
                { "System.SByte",   typeof(sbyte)   },
                { "System.Byte",    typeof(byte)    },
                { "System.Int16",   typeof(short)   },
                { "System.UInt16",  typeof(ushort)  },
                { "System.Int32",   typeof(int)     },
                { "System.UInt32",  typeof(uint)    },
                { "System.Int64",   typeof(long)    },
                { "System.UInt64",  typeof(ulong)   },
                { "System.IntPtr",  typeof(IntPtr)  },
                { "System.UIntPtr", typeof(UIntPtr) },
                { "System.Char",    typeof(char)    },
                { "System.Boolean", typeof(bool)    },
                { "System.String",  typeof(string)  },
                { "System.Single",  typeof(float)   },
                { "System.Double",  typeof(double)  },
                { "System.Decimal", typeof(decimal) }
            };

        // These static TypeRefs can be re-used anywhere *except* for references that appear
        // directly in source code (because they may have different formatting information).
        public static TypeRef ObjectRef;
        public static TypeRef VoidRef;
        public static TypeRef SByteRef;
        public static TypeRef ByteRef;
        public static TypeRef ShortRef;
        public static TypeRef UShortRef;
        public static TypeRef IntRef;
        public static TypeRef UIntRef;
        public static TypeRef LongRef;
        public static TypeRef ULongRef;
        public static TypeRef CharRef;
        public static TypeRef BoolRef;
        public static TypeRef StringRef;
        public static TypeRef FloatRef;
        public static TypeRef DoubleRef;
        public static TypeRef DecimalRef;

        public static TypeRef ArrayRef;
        public static TypeRef ValueTypeRef;
        public static TypeRef EnumRef;
        public static TypeRef Nullable1Ref;
        public static TypeRef TypeTypeRef;

        public static TypeRef Dictionary2Ref;
        public static TypeRef IEnumerableRef;
        public static TypeRef IEnumerable1Ref;
        public static TypeRef ICollectionRef;
        public static TypeRef ICollection1Ref;
        public static TypeRef IListRef;
        public static TypeRef IList1Ref;
        public static TypeRef ICloneableRef;
        public static TypeRef ISerializableRef;

        public static TypeRef FlagsAttributeRef;
        public static TypeRef DelegateRef;
        public static TypeRef MulticastDelegateRef;
        public static TypeRef AsyncCallbackRef;
        public static TypeRef IAsyncResultRef;
        public static TypeRef TypeUtilTRef;  // Needed for ManualTests to convert typeof(TypeUtil.T) to a TypeReference

        public static Dictionary<string, TypeRef> KeywordToTypeRefMap = new Dictionary<string, TypeRef>(16);
        public static TypeRef[,] CommonTypeRefMap;

        private static readonly Dictionary<Type, TypeRef> TypeToTypeRefMap = new Dictionary<Type, TypeRef>(); 
        private static readonly Dictionary<TypeDefinition, TypeRef> TypeDefinitionToTypeRefMap = new Dictionary<TypeDefinition, TypeRef>();
        private static readonly Dictionary<string, TypeDefinition> TypeNameToTypeDefinition = new Dictionary<string, TypeDefinition>(); 

        /// <summary>
        /// Initialize static <see cref="TypeRef"/>s for standard types according to the types loaded in the
        /// specified <see cref="Project"/> if <see cref="ApplicationContext.UseMonoCecilLoads"/> is true - otherwise,
        /// or if null is passed, default to the standard mscorlib types.
        /// </summary>
        public static void InitializeTypeRefs(Project project)
        {
            TypeToTypeRefMap.Clear();
            TypeDefinitionToTypeRefMap.Clear();
            TypeNameToTypeDefinition.Clear();

            ObjectRef    = FindTypeRef(project, typeof(object));
            VoidRef      = FindTypeRef(project, typeof(void));
            SByteRef     = FindTypeRef(project, typeof(sbyte));
            ByteRef      = FindTypeRef(project, typeof(byte));
            ShortRef     = FindTypeRef(project, typeof(short));
            UShortRef    = FindTypeRef(project, typeof(ushort));
            IntRef       = FindTypeRef(project, typeof(int));
            UIntRef      = FindTypeRef(project, typeof(uint));
            LongRef      = FindTypeRef(project, typeof(long));
            ULongRef     = FindTypeRef(project, typeof(ulong));
            CharRef      = FindTypeRef(project, typeof(char));
            BoolRef      = FindTypeRef(project, typeof(bool));
            StringRef    = FindTypeRef(project, typeof(string));
            FloatRef     = FindTypeRef(project, typeof(float));
            DoubleRef    = FindTypeRef(project, typeof(double));
            DecimalRef   = FindTypeRef(project, typeof(decimal));

            TypeTypeRef  = FindTypeRef(project, typeof(Type));
            ArrayRef     = FindTypeRef(project, typeof(Array));
            EnumRef      = FindTypeRef(project, typeof(Enum));
            ValueTypeRef = FindTypeRef(project, typeof(ValueType));
            Nullable1Ref = FindTypeRef(project, typeof(Nullable<>));

            Dictionary2Ref   = FindTypeRef(project, typeof(Dictionary<,>));
            IEnumerableRef   = FindTypeRef(project, typeof(IEnumerable));
            IEnumerable1Ref  = FindTypeRef(project, typeof(IEnumerable<>));
            ICollectionRef   = FindTypeRef(project, typeof(ICollection));
            ICollection1Ref  = FindTypeRef(project, typeof(ICollection<>));
            IListRef         = FindTypeRef(project, typeof(IList));
            IList1Ref        = FindTypeRef(project, typeof(IList<>));
            ICloneableRef    = FindTypeRef(project, typeof(ICloneable));
            ISerializableRef = FindTypeRef(project, typeof(ISerializable));

            FlagsAttributeRef        = FindTypeRef(project, typeof(FlagsAttribute));
            DelegateRef              = FindTypeRef(project, typeof(Delegate));
            MulticastDelegateRef     = FindTypeRef(project, typeof(MulticastDelegate));

            AsyncCallbackRef         = FindTypeRef(project, typeof(AsyncCallback));
            IAsyncResultRef          = FindTypeRef(project, typeof(IAsyncResult));
            TypeUtilTRef             = FindTypeRef(project, typeof(TypeUtil.T));

            // Initialize the keyword-to-type map.
            KeywordToTypeRefMap = new Dictionary<string, TypeRef>(16)
            {
                { "object",  ObjectRef  },
                { "void",    VoidRef    },
                { "sbyte",   SByteRef   },
                { "byte",    ByteRef    },
                { "short",   ShortRef   },
                { "ushort",  UShortRef  },
                { "int",     IntRef     },
                { "uint",    UIntRef    },
                { "long",    LongRef    },
                { "ulong",   ULongRef   },
                { "char",    CharRef    },
                { "bool",    BoolRef    },
                { "string",  StringRef  },
                { "float",   FloatRef   },
                { "double",  DoubleRef  },
                { "decimal", DecimalRef }
            };

            // Initialize the common-type map.  The TypeCode enum looks like this:
            // 0-Empty, 1-Object, 2-DBNull, 3-Boolean, 4-Char, 5-SByte, 6-Byte, 7-Int16, 8-UInt16, 9-Int32,
            // 10-UInt32, 11-Int64, 12-UInt64, 13-Single, 14-Double, 15-Decimal, 16-DateTime, 17-String
            // We will 'cheat' a bit here and use knowledge of this ordering to create a mapping table
            // for just 4-Char through 14-Double for common type calculations.
            CommonTypeRefMap = new[,]
                {  // char        sbyte       byte        short       ushort      int         uint        long        ulong       float      double     decimal
                    { IntRef,     IntRef,     IntRef,     IntRef,     IntRef,     IntRef,     UIntRef,    LongRef,    ULongRef,   FloatRef,  DoubleRef, DecimalRef },  // char
                    { IntRef,     IntRef,     IntRef,     IntRef,     IntRef,     IntRef,     LongRef,    LongRef,    ObjectRef,  FloatRef,  DoubleRef, DecimalRef },  // sbyte
                    { IntRef,     IntRef,     IntRef,     IntRef,     IntRef,     IntRef,     UIntRef,    LongRef,    ULongRef,   FloatRef,  DoubleRef, DecimalRef },  // byte
                    { IntRef,     IntRef,     IntRef,     IntRef,     IntRef,     IntRef,     LongRef,    LongRef,    ObjectRef,  FloatRef,  DoubleRef, DecimalRef },  // short
                    { IntRef,     IntRef,     IntRef,     IntRef,     IntRef,     IntRef,     UIntRef,    LongRef,    ULongRef,   FloatRef,  DoubleRef, DecimalRef },  // ushort
                    { IntRef,     IntRef,     IntRef,     IntRef,     IntRef,     IntRef,     LongRef,    LongRef,    ObjectRef,  FloatRef,  DoubleRef, DecimalRef },  // int
                    { UIntRef,    LongRef,    UIntRef,    LongRef,    UIntRef,    LongRef,    UIntRef,    LongRef,    ULongRef,   FloatRef,  DoubleRef, DecimalRef },  // uint
                    { LongRef,    LongRef,    LongRef,    LongRef,    LongRef,    LongRef,    LongRef,    LongRef,    ObjectRef,  FloatRef,  DoubleRef, DecimalRef },  // long
                    { ULongRef,   ObjectRef,  ULongRef,   ObjectRef,  ULongRef,   ObjectRef,  ULongRef,   ObjectRef,  ULongRef,   FloatRef,  DoubleRef, DecimalRef },  // ulong
                    { FloatRef,   FloatRef,   FloatRef,   FloatRef,   FloatRef,   FloatRef,   FloatRef,   FloatRef,   FloatRef,   FloatRef,  DoubleRef, ObjectRef  },  // float
                    { DoubleRef,  DoubleRef,  DoubleRef,  DoubleRef,  DoubleRef,  DoubleRef,  DoubleRef,  DoubleRef,  DoubleRef,  DoubleRef, DoubleRef, ObjectRef  },  // double
                    { DecimalRef, DecimalRef, DecimalRef, DecimalRef, DecimalRef, DecimalRef, DecimalRef, DecimalRef, DecimalRef, ObjectRef, ObjectRef, DecimalRef }   // decimal
                };
        }

        /// <summary>
        /// Initialize static <see cref="TypeRef"/>s for standard types to the standard mscorlib types.
        /// </summary>
        public static void InitializeTypeRefs()
        {
            InitializeTypeRefs(null);
        }

        /// <summary>
        /// Clear any static references to types.
        /// </summary>
        public static void ClearStaticReferences()
        {
            // Reset TypeRefs to reflection defaults to release any Mono Cecil types
            InitializeTypeRefs();
        }

        /// <summary>
        /// Find or create a <see cref="TypeRef"/> that represents the appropriate <see cref="TypeDefinition"/>/<see cref="Type"/>
        /// in the specified <see cref="Project"/> that has the same FullName as the specified <see cref="Type"/>.
        /// </summary>
        public static TypeRef FindTypeRef(Project project, Type type)
        {
            TypeRef typeRef;

            // If we're using Mono Cecil, find or create a TypeRef for the TypeDefinition corresponding to the
            // built-in type which matches the full name of the specified Type.
            if (ApplicationContext.UseMonoCecilLoads && project != null)
            {
                TypeDefinition typeDefinition = project.Find(MemberInfoUtil.GetFullName(type)) as TypeDefinition;
                if (typeDefinition != null)
                {
                    // Once a TypeRef is created for a particular TypeDefinition, always re-use it
                    if (TypeDefinitionToTypeRefMap.TryGetValue(typeDefinition, out typeRef))
                        return typeRef;
                    typeRef = new TypeRef(typeDefinition);
                    TypeDefinitionToTypeRefMap.Add(typeDefinition, typeRef);
                    // Translate any '/' for a nested type to the .NET standard '+'
                    TypeNameToTypeDefinition.Add(typeDefinition.FullName.Replace("/", "+"), typeDefinition);
                    return typeRef;
                }
            }

            // When using reflection, the 'loaded' mscorlib will always be the same as that used by the currently
            // running app, so we can just initialize using the 'typeof' type.
            // Once a TypeRef is created for a particular Type, always re-use it.
            if (TypeToTypeRefMap.TryGetValue(type, out typeRef))
                return typeRef;
            typeRef = new TypeRef(type);
            TypeToTypeRefMap.Add(type, typeRef);
            return typeRef;
        }

        /// <summary>
        /// Get the equivalent <see cref="Type"/> for the specified <see cref="TypeReference"/> (only works for primitive and built-in .NET types).
        /// </summary>
        /// <returns>The equivalent .NET type (if any), otherwise null.</returns>
        public static Type GetEquivalentType(TypeReference typeReference)
        {
            Type type;
            TypeNameToTypeMap.TryGetValue(typeReference.FullName, out type);
            return type;
        }

        #endregion

        #region /* CONSTRUCTORS */

        /// <summary>
        /// Create a <see cref="TypeRef"/> from an <see cref="ITypeDecl"/>.
        /// </summary>
        public TypeRef(ITypeDecl iTypeDecl, bool isFirstOnLine, ChildList<Expression> typeArguments, List<int> arrayRanks)
            : base(iTypeDecl, isFirstOnLine)
        {
            // If the ITypeDecl is generic, and no type arguments were specified, use the declared type parameters (including those from any
            // enclosing types).  If only local arguments were specified, then prefix the declared type parameters from any enclosing types.
            // TypeParameters won't have type arguments, and neither should a reference to an Alias, so we only need to check TypeDecls.
            if (iTypeDecl is TypeDecl && iTypeDecl.IsGenericType)
                typeArguments = DefaultTypeArguments((TypeDecl)iTypeDecl, typeArguments);

            TypeArguments = typeArguments;
            ArrayRanks = arrayRanks;
        }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from an <see cref="ITypeDecl"/>.
        /// </summary>
        public TypeRef(ITypeDecl iTypeDecl, bool isFirstOnLine, ChildList<Expression> typeArguments)
            : this(iTypeDecl, isFirstOnLine, typeArguments, null)
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from an <see cref="ITypeDecl"/>.
        /// </summary>
        public TypeRef(ITypeDecl iTypeDecl, bool isFirstOnLine)
            : this(iTypeDecl, isFirstOnLine, (ChildList<Expression>)null, null)
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from an <see cref="ITypeDecl"/>.
        /// </summary>
        public TypeRef(ITypeDecl iTypeDecl)
            : this(iTypeDecl, false, (ChildList<Expression>)null, null)
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from an <see cref="ITypeDecl"/>.
        /// </summary>
        public TypeRef(ITypeDecl iTypeDecl, ChildList<Expression> typeArguments, List<int> arrayRanks)
            : this(iTypeDecl, false, typeArguments, arrayRanks)
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from an <see cref="ITypeDecl"/>.
        /// </summary>
        public TypeRef(ITypeDecl iTypeDecl, ChildList<Expression> typeArguments)
            : this(iTypeDecl, false, typeArguments, null)
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from an <see cref="ITypeDecl"/>.
        /// </summary>
        public TypeRef(ITypeDecl iTypeDecl, List<int> arrayRanks)
            : this(iTypeDecl, false, null, arrayRanks)
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from an <see cref="ITypeDecl"/>.
        /// </summary>
        public TypeRef(ITypeDecl iTypeDecl, bool isFirstOnLine, params Expression[] typeArguments)
            : this(iTypeDecl, isFirstOnLine, ((typeArguments != null && typeArguments.Length > 0) ? new ChildList<Expression>(typeArguments) : null))
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from an <see cref="ITypeDecl"/>.
        /// </summary>
        public TypeRef(ITypeDecl iTypeDecl, params Expression[] typeArguments)
            : this(iTypeDecl, false, ((typeArguments != null && typeArguments.Length > 0) ? new ChildList<Expression>(typeArguments) : null))
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from an <see cref="ITypeDecl"/>.
        /// </summary>
        public TypeRef(ITypeDecl iTypeDecl, bool isFirstOnLine, params int[] arrayRanks)
            : this(iTypeDecl, isFirstOnLine, null, ((arrayRanks != null && arrayRanks.Length > 0) ? new List<int>(arrayRanks) : null))
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from an <see cref="ITypeDecl"/>.
        /// </summary>
        public TypeRef(ITypeDecl iTypeDecl, params int[] arrayRanks)
            : this(iTypeDecl, false, null, ((arrayRanks != null && arrayRanks.Length > 0) ? new List<int>(arrayRanks) : null))
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="TypeDefinition"/>.
        /// To create a <see cref="TypeRef"/> from a <see cref="GenericParameter"/>, use one of the TypeRef.Create() factory methods,
        /// so it can create the appropriate <see cref="OpenTypeParameterRef"/>, or use a constructor of <see cref="OpenTypeParameterRef"/>.
        /// </summary>
        public TypeRef(TypeDefinition typeDefinition, bool isFirstOnLine, ChildList<Expression> typeArguments, List<int> arrayRanks)
            : base((TypeDefinition)null, isFirstOnLine)
        {
            // If the type is generic, and no type arguments were specified, use the existing arguments (including those
            // from any enclosing types).  If only local arguments were specified, then prefix those from any enclosing types.
            if (typeDefinition.HasGenericParameters)
                typeArguments = DefaultTypeArguments(typeDefinition, typeArguments);

            _reference = typeDefinition;
            TypeArguments = typeArguments;
            ArrayRanks = arrayRanks;
        }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="TypeDefinition"/>.
        /// To create a <see cref="TypeRef"/> from a <see cref="GenericParameter"/>, use one of the TypeRef.Create() factory methods,
        /// so it can create the appropriate <see cref="OpenTypeParameterRef"/>, or use a constructor of <see cref="OpenTypeParameterRef"/>.
        /// </summary>
        public TypeRef(TypeDefinition typeDefinition, bool isFirstOnLine, ChildList<Expression> typeArguments)
            : this(typeDefinition, isFirstOnLine, typeArguments, null)
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="TypeDefinition"/>.
        /// To create a <see cref="TypeRef"/> from a <see cref="GenericParameter"/>, use one of the TypeRef.Create() factory methods,
        /// so it can create the appropriate <see cref="OpenTypeParameterRef"/>, or use a constructor of <see cref="OpenTypeParameterRef"/>.
        /// </summary>
        public TypeRef(TypeDefinition typeDefinition, bool isFirstOnLine)
            : this(typeDefinition, isFirstOnLine, (ChildList<Expression>)null, null)
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="TypeDefinition"/>.
        /// To create a <see cref="TypeRef"/> from a <see cref="GenericParameter"/>, use one of the TypeRef.Create() factory methods,
        /// so it can create the appropriate <see cref="OpenTypeParameterRef"/>, or use a constructor of <see cref="OpenTypeParameterRef"/>.
        /// </summary>
        public TypeRef(TypeDefinition typeDefinition)
            : this(typeDefinition, false, (ChildList<Expression>)null, null)
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="TypeDefinition"/>.
        /// To create a <see cref="TypeRef"/> from a <see cref="GenericParameter"/>, use one of the TypeRef.Create() factory methods,
        /// so it can create the appropriate <see cref="OpenTypeParameterRef"/>, or use a constructor of <see cref="OpenTypeParameterRef"/>.
        /// </summary>
        public TypeRef(TypeDefinition typeDefinition, ChildList<Expression> typeArguments, List<int> arrayRanks)
            : this(typeDefinition, false, typeArguments, arrayRanks)
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="TypeDefinition"/>.
        /// To create a <see cref="TypeRef"/> from a <see cref="GenericParameter"/>, use one of the TypeRef.Create() factory methods,
        /// so it can create the appropriate <see cref="OpenTypeParameterRef"/>, or use a constructor of <see cref="OpenTypeParameterRef"/>.
        /// </summary>
        public TypeRef(TypeDefinition typeDefinition, ChildList<Expression> typeArguments)
            : this(typeDefinition, false, typeArguments, null)
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="TypeDefinition"/>.
        /// To create a <see cref="TypeRef"/> from a <see cref="GenericParameter"/>, use one of the TypeRef.Create() factory methods,
        /// so it can create the appropriate <see cref="OpenTypeParameterRef"/>, or use a constructor of <see cref="OpenTypeParameterRef"/>.
        /// </summary>
        public TypeRef(TypeDefinition typeDefinition, List<int> arrayRanks)
            : this(typeDefinition, false, null, arrayRanks)
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="TypeDefinition"/>.
        /// To create a <see cref="TypeRef"/> from a <see cref="GenericParameter"/>, use one of the TypeRef.Create() factory methods,
        /// so it can create the appropriate <see cref="OpenTypeParameterRef"/>, or use a constructor of <see cref="OpenTypeParameterRef"/>.
        /// </summary>
        public TypeRef(TypeDefinition typeDefinition, bool isFirstOnLine, params Expression[] typeArguments)
            : this(typeDefinition, isFirstOnLine, ((typeArguments != null && typeArguments.Length > 0) ? new ChildList<Expression>(typeArguments) : null))
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="TypeDefinition"/>.
        /// To create a <see cref="TypeRef"/> from a <see cref="GenericParameter"/>, use one of the TypeRef.Create() factory methods,
        /// so it can create the appropriate <see cref="OpenTypeParameterRef"/>, or use a constructor of <see cref="OpenTypeParameterRef"/>.
        /// </summary>
        public TypeRef(TypeDefinition typeDefinition, params Expression[] typeArguments)
            : this(typeDefinition, false, ((typeArguments != null && typeArguments.Length > 0) ? new ChildList<Expression>(typeArguments) : null))
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="TypeDefinition"/>.
        /// To create a <see cref="TypeRef"/> from a <see cref="GenericParameter"/>, use one of the TypeRef.Create() factory methods,
        /// so it can create the appropriate <see cref="OpenTypeParameterRef"/>, or use a constructor of <see cref="OpenTypeParameterRef"/>.
        /// </summary>
        public TypeRef(TypeDefinition typeDefinition, bool isFirstOnLine, params int[] arrayRanks)
            : this(typeDefinition, isFirstOnLine, null, ((arrayRanks != null && arrayRanks.Length > 0) ? new List<int>(arrayRanks) : null))
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="TypeDefinition"/>.
        /// To create a <see cref="TypeRef"/> from a <see cref="GenericParameter"/>, use one of the TypeRef.Create() factory methods,
        /// so it can create the appropriate <see cref="OpenTypeParameterRef"/>, or use a constructor of <see cref="OpenTypeParameterRef"/>.
        /// </summary>
        public TypeRef(TypeDefinition typeDefinition, params int[] arrayRanks)
            : this(typeDefinition, false, null, ((arrayRanks != null && arrayRanks.Length > 0) ? new List<int>(arrayRanks) : null))
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="GenericParameter"/>.
        /// </summary>
        protected TypeRef(GenericParameter genericParameter, bool isFirstOnLine, List<int> arrayRanks)
            : base((GenericParameter)null, isFirstOnLine)
        {
            _reference = genericParameter;
            ArrayRanks = arrayRanks;
        }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="GenericParameter"/>.
        /// </summary>
        protected TypeRef(GenericParameter genericParameter, bool isFirstOnLine)
            : base((GenericParameter)null, isFirstOnLine)
        {
            _reference = genericParameter;
        }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="GenericParameter"/>.
        /// </summary>
        protected TypeRef(GenericParameter genericParameter)
            : base((GenericParameter)null, false)
        {
            _reference = genericParameter;
        }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="GenericParameter"/>.
        /// </summary>
        protected TypeRef(GenericParameter genericParameter, bool isFirstOnLine, params int[] arrayRanks)
            : this(genericParameter, isFirstOnLine, ((arrayRanks != null && arrayRanks.Length > 0) ? new List<int>(arrayRanks) : null))
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// If the <see cref="Type"/> might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>)
        /// or an array of one of those, use one of the TypeRef.Create() factory methods instead.
        /// </summary>
        public TypeRef(Type type, bool isFirstOnLine, ChildList<Expression> typeArguments, List<int> arrayRanks)
            : base((Type)null, isFirstOnLine)
        {
            // If the type is an array, and no array ranks were specified, use the existing array ranks (otherwise override them)
            if (type.IsArray)
            {
                bool useExistingRanks = (arrayRanks == null);
                if (useExistingRanks)
                    arrayRanks = new List<int>();
                do
                {
                    if (useExistingRanks)
                        arrayRanks.Add(type.GetArrayRank());
                    type = type.GetElementType();
                }
                while (type.IsArray);
            }

            // Dereference (remove the trailing '&') if it's a reference type
            if (type.IsByRef)
                type = type.GetElementType();

            // If the type is generic, and no type arguments were specified, use the existing arguments (including those
            // from any enclosing types).  If only local arguments were specified, then prefix those from any enclosing types.
            if (type.IsGenericType)
                typeArguments = DefaultTypeArguments(type, typeArguments);

            _reference = type;
            TypeArguments = typeArguments;
            ArrayRanks = arrayRanks;
        }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// If the <see cref="Type"/> might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>)
        /// or an array of one of those, use one of the TypeRef.Create() factory methods instead.
        /// </summary>
        public TypeRef(Type type, bool isFirstOnLine, ChildList<Expression> typeArguments)
            : this(type, isFirstOnLine, typeArguments, null)
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// If the <see cref="Type"/> might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>)
        /// or an array of one of those, use one of the TypeRef.Create() factory methods instead.
        /// </summary>
        public TypeRef(Type type, bool isFirstOnLine)
            : this(type, isFirstOnLine, (ChildList<Expression>)null, null)
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// If the <see cref="Type"/> might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>)
        /// or an array of one of those, use one of the TypeRef.Create() factory methods instead.
        /// </summary>
        public TypeRef(Type type, ChildList<Expression> typeArguments, List<int> arrayRanks)
            : this(type, false, typeArguments, arrayRanks)
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// If the <see cref="Type"/> might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>)
        /// or an array of one of those, use one of the TypeRef.Create() factory methods instead.
        /// </summary>
        public TypeRef(Type type, ChildList<Expression> typeArguments)
            : this(type, false, typeArguments, null)
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// If the <see cref="Type"/> might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>)
        /// or an array of one of those, use one of the TypeRef.Create() factory methods instead.
        /// </summary>
        public TypeRef(Type type)
            : this(type, false, (ChildList<Expression>)null, null)
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// If the <see cref="Type"/> might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>)
        /// or an array of one of those, use one of the TypeRef.Create() factory methods instead.
        /// </summary>
        public TypeRef(Type type, List<int> arrayRanks)
            : this(type, false, null, arrayRanks)
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// If the <see cref="Type"/> might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>)
        /// or an array of one of those, use one of the TypeRef.Create() factory methods instead.
        /// </summary>
        public TypeRef(Type type, bool isFirstOnLine, params Expression[] typeArguments)
            : this(type, isFirstOnLine, ((typeArguments != null && typeArguments.Length > 0) ? new ChildList<Expression>(typeArguments) : null))
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// If the <see cref="Type"/> might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>)
        /// or an array of one of those, use one of the TypeRef.Create() factory methods instead.
        /// </summary>
        public TypeRef(Type type, params Expression[] typeArguments)
            : this(type, false, ((typeArguments != null && typeArguments.Length > 0) ? new ChildList<Expression>(typeArguments) : null))
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// If the <see cref="Type"/> might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>)
        /// or an array of one of those, use one of the TypeRef.Create() factory methods instead.
        /// </summary>
        public TypeRef(Type type, bool isFirstOnLine, params int[] arrayRanks)
            : this(type, isFirstOnLine, null, ((arrayRanks != null && arrayRanks.Length > 0) ? new List<int>(arrayRanks) : null))
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// If the <see cref="Type"/> might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>)
        /// or an array of one of those, use one of the TypeRef.Create() factory methods instead.
        /// </summary>
        public TypeRef(Type type, params int[] arrayRanks)
            : this(type, false, null, ((arrayRanks != null && arrayRanks.Length > 0) ? new List<int>(arrayRanks) : null))
        { }

        /// <summary>
        /// Create a <see cref="TypeRef"/> from a constant value.
        /// </summary>
        /// <remarks>
        /// The <see cref="TypeRef"/> will reference the constant instance object, the type of which will be retrieved
        /// as needed using <see cref="object.GetType()"/>.
        /// </remarks>
        public TypeRef(object constantValue)
            : base(constantValue ?? typeof(object))
        {
            _formatFlags |= FormatFlags.Const;
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from the specified type and constant value.
        /// </summary>
        /// <remarks>
        /// If the specified TypeRef refers to an Enum type, the created TypeRef will reference a special EnumConstant
        /// instance, which will hold the TypeRef of the enum type plus an instance object of the enum's underlying
        /// type holding the constant value (it's not possible to reference an enum value member instead, because
        /// the constant value of an enum might be outside the range of its members, or not have a one-to-one mapping
        /// if it's a flags enum; it's also not possible to construct an instance of the enum type with the proper
        /// constant value, since an EnumDecl might not be in a state that allows an instance to be created, and it
        /// could be modified by editing, thus invalidating the type).
        /// Otherwise, if the specified constant value isn't null, an attempt will be made to convert it to the
        /// specified TypeRef.  If the constant value is null, or the conversion attempt fails, then a null constant
        /// of the specified TypeRef will be created.
        /// </remarks>
        public TypeRef(TypeRef typeRef, object constantValue)
            : base(null)
        {
            bool isOK = true;
            if (typeRef.IsEnum)
                _reference = new EnumConstant(typeRef, constantValue);
            else
            {
                // Convert the constant value to the specified type if possible
                if (constantValue != null)
                {
                    // If the destination is type 'object', the only valid constant type is 'null', so skip this logic
                    // (which means that a numeric constant cast to type 'object' results in a non-constant 'object').
                    if (!typeRef.IsSameRef(ObjectRef))
                    {
                        if (constantValue is EnumConstant)
                            constantValue = ((EnumConstant)constantValue).ConstantValue;
                        _reference = ChangeTypeOfConstant(constantValue, typeRef);
                    }
                    // If the conversion fails, lose the constant status
                    if (_reference == null)
                        isOK = false;
                }
                // If the constant value is null, or the conversion above failed, create a copy of specified type, copying
                // the internals of the passed TypeRef.  If the conversion failed, it will remain non-const, but if it's
                // a null constant, the const flag will be set below on exit.
                if (_reference == null)
                {
                    _reference = typeRef._reference;
                    if (typeRef._arrayRanks != null)
                        _arrayRanks = new List<int>(typeRef._arrayRanks);
                    if (typeRef._typeArguments != null)
                        _typeArguments = ChildListHelpers.Clone(typeRef._typeArguments, this);
                }
            }
            if (isOK)
                _formatFlags |= FormatFlags.Const;
        }

        #endregion

        #region /* PROPERTIES */

        /// <summary>
        /// The name of the <see cref="TypeRef"/>.
        /// </summary>
        public override string Name
        {
            get
            {
                if (_reference is ITypeDecl)
                    return ((ITypeDecl)_reference).Name;
                if (_reference is TypeReference)  // TypeDefinition or GenericParameter
                {
                    TypeReference typeReference = (TypeReference)_reference;
                    return (typeReference.HasGenericParameters ? TypeDefinitionUtil.NonGenericName(typeReference) : typeReference.Name);
                }
                if (_reference is Type)
                {
                    Type type = (Type)_reference;
                    return (type.IsGenericType ? TypeUtil.NonGenericName(type) : type.Name);
                }
                if (_reference is EnumConstant)  // Enum constant
                    return ((EnumConstant)_reference).EnumTypeRef.Name;
                return (_reference != null ? _reference.GetType().Name : null);  // Constant
            }
        }

        /// <summary>
        /// The descriptive category of the <see cref="SymbolicRef"/>.
        /// </summary>
        public override string Category
        {
            get
            {
                if (_reference is ITypeDecl)
                    return ((ITypeDecl)_reference).Category;
                if (_reference is TypeDefinition)
                    return MemberReferenceUtil.GetCategory((TypeDefinition)_reference);
                if (_reference is GenericParameter)
                    return GenericParameterUtil.GetCategory((GenericParameter)_reference);
                if (_reference is Type)
                    return MemberInfoUtil.GetCategory((Type)_reference);
                if (_reference is EnumConstant)
                    return "enum constant";
                return "constant";
            }
        }

        /// <summary>
        /// The associated <see cref="Namespace"/> name.
        /// </summary>
        public virtual string NamespaceName
        {
            get
            {
                if (_reference is ITypeDecl)
                {
                    Namespace @namespace = ((ITypeDecl)_reference).GetNamespace();
                    return (@namespace != null ? @namespace.FullName : null);
                }
                if (_reference is TypeReference)  // TypeDefinition or GenericParameter
                    return ((TypeReference)_reference).Namespace;
                if (_reference is Type)
                    return ((Type)_reference).Namespace;
                if (_reference is EnumConstant)
                    return ((EnumConstant)_reference).EnumTypeRef.NamespaceName;
                return _reference.GetType().Namespace;
            }
        }

        /// <summary>
        /// True if the referenced type is abstract.
        /// </summary>
        public bool IsAbstract
        {
            get
            {
                if (HasArrayRanks) return false;
                object reference = GetReferencedType();
                if (reference is ITypeDecl)
                    return ((ITypeDecl)reference).IsAbstract;
                if (reference is TypeDefinition)
                    return ((TypeDefinition)reference).IsAbstract;
                if (reference is Type)
                    return ((Type)reference).IsAbstract;
                return false;
            }
        }

        /// <summary>
        /// True if the referenced type is a built-in type (has a keyword). The built-in types are:
        /// object, void, sbyte, byte, short, ushort, int, uint, long, ulong, char, bool, string, float, double, decimal
        /// </summary>
        public override bool IsBuiltInType
        {
            get
            {
                if (HasArrayRanks) return false;
                // Check the type name first for efficiency, then verify the namespace name.
                // We can't use IsPrimitive, because it's missing a few types and has a couple that aren't built-ins.
                return (TypeNameToKeywordMap.ContainsKey(Name) && NamespaceName == "System");
            }
        }

        /// <summary>
        /// True if the referenced type is a class.
        /// </summary>
        public bool IsClass
        {
            get
            {
                if (HasArrayRanks) return false;
                object reference = GetReferencedType();
                if (reference is ITypeDecl)
                    return ((ITypeDecl)reference).IsClass;
                if (reference is TypeDefinition)
                    return (((TypeDefinition)reference).IsClass && !((TypeDefinition)reference).IsValueType);
                if (reference is Type)
                    return ((Type)reference).IsClass;
                return false;
            }
        }

        /// <summary>
        /// True if the referenced type is a user-defined class (excludes 'object' and 'string').
        /// </summary>
        public bool IsUserClass
        {
            get
            {
                if (HasArrayRanks) return false;
                object reference = GetReferencedType();
                if (reference is ITypeDecl)
                    return ((ITypeDecl)reference).IsClass;
                if (reference is TypeDefinition)
                    return TypeDefinitionUtil.IsUserClass((TypeDefinition)reference);
                if (reference is Type)
                    return TypeUtil.IsUserClass((Type)reference);
                return false;
            }
        }

        /// <summary>
        /// True if the referenced type is a delegate type.
        /// </summary>
        public override bool IsDelegateType
        {
            get
            {
                if (HasArrayRanks) return false;
                object reference = GetReferencedType();
                if (reference is ITypeDecl)
                    return ((ITypeDecl)reference).IsDelegateType;
                if (reference is TypeDefinition)
                    return TypeDefinitionUtil.IsDelegateType((TypeDefinition)reference);
                if (reference is Type)
                    return TypeUtil.IsDelegateType((Type)reference);
                return false;
            }
        }

        /// <summary>
        /// True if the referenced type is an enum.
        /// </summary>
        public bool IsEnum
        {
            get
            {
                if (HasArrayRanks) return false;
                object reference = GetReferencedType();
                if (reference is ITypeDecl)
                    return ((ITypeDecl)reference).IsEnum;
                if (reference is TypeDefinition)
                    return ((TypeDefinition)reference).IsEnum;
                if (reference is Type)
                    return ((Type)reference).IsEnum;
                return false;
            }
        }

        /// <summary>
        /// True if the referenced type is a bit-flags enum.
        /// </summary>
        public bool IsBitFlagsEnum
        {
            get
            {
                if (IsEnum)
                {
                    if (_reference is EnumDecl)
                        return ((EnumDecl)_reference).IsBitFlags;
                    if (_reference is TypeDefinition)
                        return TypeDefinitionUtil.IsBitFlagsEnum((TypeDefinition)_reference);
                    if (_reference is Type)
                        return TypeUtil.IsBitFlagsEnum((Type)_reference);
                    if (_reference is EnumConstant)
                        return ((EnumConstant)_reference).EnumTypeRef.IsBitFlagsEnum;
                }
                return false;
            }
        }

        /// <summary>
        /// True if the referenced type is a generic type parameter.
        /// </summary>
        public virtual bool IsGenericParameter
        {
            get
            {
                object reference = GetReferencedType();
                if (reference is ITypeDecl)
                    return ((ITypeDecl)reference).IsGenericParameter;
                if (reference is TypeReference)  // TypeDefinition or GenericParameter
                    return ((TypeReference)reference).IsGenericParameter;
                if (reference is Type)
                    return ((Type)reference).IsGenericParameter;
                return false;
            }
        }

        /// <summary>
        /// True if the type is a generic type (meaning that either it or an enclosing type has type arguments).
        /// </summary>
        public bool IsGenericType
        {
            get
            {
                object reference = GetReferencedType();
                if (reference is ITypeDecl)
                    return ((ITypeDecl)reference).IsGenericType;
                if (reference is TypeReference)  // TypeDefinition or GenericParameter
                    return ((TypeReference)reference).HasGenericParameters;
                if (reference is Type)
                    return ((Type)reference).IsGenericType;
                return false;
            }
        }

        /// <summary>
        /// True if the referenced type is an interface.
        /// </summary>
        public override bool IsInterface
        {
            get
            {
                if (HasArrayRanks) return false;
                object reference = GetReferencedType();
                if (reference is ITypeDecl)
                    return ((ITypeDecl)reference).IsInterface;
                if (reference is TypeDefinition)
                    return ((TypeDefinition)reference).IsInterface;
                if (reference is Type)
                    return ((Type)reference).IsInterface;
                return false;
            }
        }

        /// <summary>
        /// True if the referenced type is a nested type.
        /// </summary>
        public bool IsNested
        {
            get
            {
                object reference = GetReferencedType();
                if (reference is ITypeDecl)
                    return ((ITypeDecl)reference).IsNested;
                if (reference is TypeReference)  // TypeDefinition or GenericParameter
                    return ((TypeReference)reference).IsNested;
                if (reference is Type)
                    return ((Type)reference).IsNested;
                return false;
            }
        }

        /// <summary>
        /// True if the referenced type is a nullable type.
        /// </summary>
        public override bool IsNullableType
        {
            get { return (Name == "Nullable" && NamespaceName == "System" && _typeArguments != null && _typeArguments.Count == 1 && _typeArguments[0] != null); }
        }

        /// <summary>
        /// True if the referenced type is a partial type.
        /// </summary>
        public bool IsPartial
        {
            get
            {
                object reference = GetReferencedType();
                return (reference is ITypeDecl && ((ITypeDecl)reference).IsPartial);
            }
        }

        /// <summary>
        /// True if the type is Primitive. The Primitive Types are:
        /// sbyte, byte, short, ushort, int, uint, long, ulong, IntPtr, UIntPtr, char, bool, float, double.
        /// The following are NOT primitive types: object, void, string, decimal
        ///  </summary>
        public bool IsPrimitive
        {
            get
            {
                if (HasArrayRanks) return false;
                object reference = GetReferencedType();
                if (reference is ITypeDecl)
                    return (PrimitiveTypeNames.Contains(((ITypeDecl)reference).Name) && ((ITypeDecl)reference).GetNamespace().Name == "System");
                if (reference is TypeReference)  // TypeDefinition or GenericParameter
                    return ((TypeReference)reference).IsPrimitive;
                if (reference is Type)
                    return ((Type)reference).IsPrimitive;
                return false;
            }
        }

        /// <summary>
        /// True if the referenced type is a user-defined struct (excludes primitive types including 'void' and 'decimal', and enums).
        /// </summary>
        public bool IsUserStruct
        {
            get
            {
                if (HasArrayRanks) return false;
                object reference = GetReferencedType();
                if (reference is ITypeDecl)
                    return ((ITypeDecl)reference).IsStruct;
                if (reference is TypeDefinition)
                    return TypeDefinitionUtil.IsUserStruct((TypeDefinition)reference);
                if (reference is Type)
                    return TypeUtil.IsUserStruct((Type)reference);
                return false;
            }
        }

        /// <summary>
        /// True if the referenced type is a value type.
        /// </summary>
        public virtual bool IsValueType
        {
            get
            {
                // Note that we also treat ValueType as a value type, even though IsValueType is false for this
                // system type, since it's actually a class (even though it's the base class of all value types).
                if (HasArrayRanks) return false;
                object reference = GetReferencedType();
                if (reference is ITypeDecl)
                    return ((ITypeDecl)reference).IsValueType;
                if (reference is TypeDefinition)
                {
                    TypeDefinition typeDefinition = (TypeDefinition)reference;
                    return (typeDefinition.IsValueType || typeDefinition.FullName == "System.ValueType");
                }
                if (reference is Type)
                {
                    Type type = (Type)reference;
                    return (type.IsValueType || (type.Name == "ValueType" && type.Namespace == "System"));
                }
                return false;
            }
        }

        /// <summary>
        /// True if the referenced type has a constant value.
        /// </summary>
        public override bool IsConst
        {
            get { return (_formatFlags.HasFlag(FormatFlags.Const)); }
        }

        /// <summary>
        /// True if the referenced type is static.
        /// </summary>
        public override bool IsStatic
        {
            get
            {
                if (HasArrayRanks) return GetElementType().IsStatic;
                object reference = GetReferencedType();
                if (reference is IModifiers)
                    return ((IModifiers)reference).IsStatic;
                if (reference is TypeDefinition)
                    return TypeDefinitionUtil.IsStatic((TypeDefinition)reference);
                if (reference is Type)
                    return TypeUtil.IsStatic((Type)reference);
                return false;
            }
        }

        /// <summary>
        /// True if the referenced type has public access.
        /// </summary>
        public override bool IsPublic
        {
            get
            {
                if (HasArrayRanks) return GetElementType().IsPublic;
                object reference = GetReferencedType();
                if (reference is IModifiers)
                    return ((IModifiers)reference).IsPublic;
                if (reference is TypeDefinition)
                    return ((TypeDefinition)reference).IsPublic;
                if (reference is Type)
                    return ((Type)reference).IsPublic;
                return false;
            }
        }

        /// <summary>
        /// True if the referenced type has private access.
        /// </summary>
        public override bool IsPrivate
        {
            get
            {
                if (HasArrayRanks) return GetElementType().IsPrivate;
                object reference = GetReferencedType();
                if (reference is IModifiers)
                    return ((IModifiers)reference).IsPrivate;
                if (reference is TypeDefinition)
                    return TypeDefinitionUtil.IsPrivate((TypeDefinition)reference);
                if (reference is Type)
                    return TypeUtil.IsPrivate((Type)reference);
                return false;
            }
        }

        /// <summary>
        /// True if the referenced type has protected access.
        /// </summary>
        public override bool IsProtected
        {
            get
            {
                if (HasArrayRanks) return GetElementType().IsProtected;
                object reference = GetReferencedType();
                if (reference is IModifiers)
                    return ((IModifiers)reference).IsProtected;
                if (reference is TypeDefinition)
                    return TypeDefinitionUtil.IsProtected((TypeDefinition)reference);
                if (reference is Type)
                    return TypeUtil.IsProtected((Type)reference);
                return false;
            }
        }

        /// <summary>
        /// True if the referenced type has internal access.
        /// </summary>
        public override bool IsInternal
        {
            get
            {
                if (HasArrayRanks) return GetElementType().IsInternal;
                object reference = GetReferencedType();
                if (reference is IModifiers)
                    return ((IModifiers)reference).IsInternal;
                if (reference is TypeDefinition)
                    return TypeDefinitionUtil.IsInternal((TypeDefinition)reference);
                if (reference is Type)
                    return TypeUtil.IsInternal((Type)reference);
                return false;
            }
        }

        #endregion

        #region /* STATIC METHODS */

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="TypeReference"/>.
        /// This factory method handles <see cref="TypeDefinition"/>s, <see cref="GenericParameter"/>s (returning an <see cref="OpenTypeParameterRef"/>),
        /// <see cref="TypeReference"/>s (resolving them to a <see cref="TypeDefinition"/>), or arrays of any of those.  For a known <see cref="TypeDefinition"/>,
        /// you may use a 'new TypeRef()' constructor for efficiency.
        /// </summary>
        /// <returns>The created <see cref="TypeRef"/> or derived type, or an <see cref="UnresolvedRef"/> if the <see cref="TypeReference"/> couldn't be resolved.</returns>
        public static TypeRefBase Create(TypeReference typeReference, bool isFirstOnLine, ChildList<Expression> typeArguments, List<int> arrayRanks)
        {
            if (typeReference == null)
                return null;

            TypeReference originalTypeReference = typeReference;
            try
            {
                // A TypeReference might be an actual TypeDefinition, or it might be a TypeSpecification (such as an ArrayType, ByReferenceType, PointerType,
                // or GenericTypeInstance), or it might be an actual reference to one of those.

                // If the type is an array, and no array ranks were specified, use the existing array ranks (otherwise override them)
                if (typeReference.IsArray)
                {
                    bool useExistingRanks = (arrayRanks == null);
                    if (useExistingRanks)
                        arrayRanks = new List<int>();
                    do
                    {
                        ArrayType arrayType = (ArrayType)typeReference;
                        if (useExistingRanks)
                            arrayRanks.Add(arrayType.Rank);
                        typeReference = arrayType.ElementType;
                    }
                    while (typeReference.IsArray);
                }

                // Dereference (remove the trailing '&') if it's a reference type
                if (typeReference.IsByReference)
                    typeReference = ((ByReferenceType)typeReference).ElementType;

                // Create a reference of the appropriate type
                if (typeReference.IsGenericParameter)
                    return new TypeParameterRef((GenericParameter)typeReference, isFirstOnLine, arrayRanks);  // Ignore any type arguments in this case
                if (typeReference.IsGenericInstance || typeReference.HasGenericParameters)
                {
                    if (typeReference is GenericInstanceType)
                    {
                        // Use any type arguments in the type if none were specified
                        if (typeArguments == null)
                            typeArguments = DefaultTypeArguments((GenericInstanceType)typeReference, null);

                        // Resolve to the TypeDefinition
                        typeReference = typeReference.Resolve();
                    }
                    else
                    {
                        // Resolve to the TypeDefinition
                        typeReference = typeReference.Resolve();

                        // Use any type arguments in the type if none were specified
                        if (typeArguments == null && typeReference != null)
                            typeArguments = DefaultTypeArguments((TypeDefinition)typeReference, null);
                    }
                }
                else
                {
                    // Resolve to the TypeDefinition
                    typeReference = typeReference.Resolve();
                }
            }
            catch (Exception ex)
            {
                Log.Exception(ex, "resolving TypeReference '" + (typeReference != null ? typeReference.Name : "") + "'");
                typeReference = null;
            }
            if (typeReference != null)
                return new TypeRef((TypeDefinition)typeReference, isFirstOnLine, typeArguments, arrayRanks);
            return new UnresolvedRef(originalTypeReference.Name, isFirstOnLine, ResolveCategory.Type) { TypeArguments = typeArguments, ArrayRanks = arrayRanks };
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="TypeReference"/>.
        /// This factory method handles <see cref="TypeDefinition"/>s, <see cref="GenericParameter"/>s (returning an <see cref="OpenTypeParameterRef"/>),
        /// <see cref="TypeReference"/>s (resolving them to a <see cref="TypeDefinition"/>), or arrays of any of those.  For a known <see cref="TypeDefinition"/>,
        /// you may use a 'new TypeRef()' constructor for efficiency.
        /// </summary>
        /// <returns>The created <see cref="TypeRef"/> or derived type, or an <see cref="UnresolvedRef"/> if the <see cref="TypeReference"/> couldn't be resolved.</returns>
        public static TypeRefBase Create(TypeReference typeReference, bool isFirstOnLine, ChildList<Expression> typeArguments)
        {
            return Create(typeReference, isFirstOnLine, typeArguments, null);
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="TypeReference"/>.
        /// This factory method handles <see cref="TypeDefinition"/>s, <see cref="GenericParameter"/>s (returning an <see cref="OpenTypeParameterRef"/>),
        /// <see cref="TypeReference"/>s (resolving them to a <see cref="TypeDefinition"/>), or arrays of any of those.  For a known <see cref="TypeDefinition"/>,
        /// you may use a 'new TypeRef()' constructor for efficiency.
        /// </summary>
        /// <returns>The created <see cref="TypeRef"/> or derived type, or an <see cref="UnresolvedRef"/> if the <see cref="TypeReference"/> couldn't be resolved.</returns>
        public static TypeRefBase Create(TypeReference typeReference, bool isFirstOnLine)
        {
            return Create(typeReference, isFirstOnLine, (ChildList<Expression>)null, null);
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="TypeReference"/>.
        /// This factory method handles <see cref="TypeDefinition"/>s, <see cref="GenericParameter"/>s (returning an <see cref="OpenTypeParameterRef"/>),
        /// <see cref="TypeReference"/>s (resolving them to a <see cref="TypeDefinition"/>), or arrays of any of those.  For a known <see cref="TypeDefinition"/>,
        /// you may use a 'new TypeRef()' constructor for efficiency.
        /// </summary>
        /// <returns>The created <see cref="TypeRef"/> or derived type, or an <see cref="UnresolvedRef"/> if the <see cref="TypeReference"/> couldn't be resolved.</returns>
        public static TypeRefBase Create(TypeReference typeReference)
        {
            return Create(typeReference, false, (ChildList<Expression>)null, null);
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="TypeReference"/>.
        /// This factory method handles <see cref="TypeDefinition"/>s, <see cref="GenericParameter"/>s (returning an <see cref="OpenTypeParameterRef"/>),
        /// <see cref="TypeReference"/>s (resolving them to a <see cref="TypeDefinition"/>), or arrays of any of those.  For a known <see cref="TypeDefinition"/>,
        /// you may use a 'new TypeRef()' constructor for efficiency.
        /// </summary>
        public static TypeRefBase Create(TypeReference typeReference, ChildList<Expression> typeArguments, List<int> arrayRanks)
        {
            return Create(typeReference, false, typeArguments, arrayRanks);
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="TypeReference"/>.
        /// This factory method handles <see cref="TypeDefinition"/>s, <see cref="GenericParameter"/>s (returning an <see cref="OpenTypeParameterRef"/>),
        /// <see cref="TypeReference"/>s (resolving them to a <see cref="TypeDefinition"/>), or arrays of any of those.  For a known <see cref="TypeDefinition"/>,
        /// you may use a 'new TypeRef()' constructor for efficiency.
        /// </summary>
        public static TypeRefBase Create(TypeReference typeReference, ChildList<Expression> typeArguments)
        {
            return Create(typeReference, false, typeArguments, null);
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="TypeReference"/>.
        /// This factory method handles <see cref="TypeDefinition"/>s, <see cref="GenericParameter"/>s (returning an <see cref="OpenTypeParameterRef"/>),
        /// <see cref="TypeReference"/>s (resolving them to a <see cref="TypeDefinition"/>), or arrays of any of those.  For a known <see cref="TypeDefinition"/>,
        /// you may use a 'new TypeRef()' constructor for efficiency.
        /// </summary>
        public static TypeRefBase Create(TypeReference typeReference, bool isFirstOnLine, params Expression[] typeArguments)
        {
            // No need to check 'typeArguments' for null, because a different constructor would have been called.
            // Convert the array of expressions to a ChildList so we can use the factory method above.
            return Create(typeReference, isFirstOnLine, new ChildList<Expression>(typeArguments));
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="TypeReference"/>.
        /// This factory method handles <see cref="TypeDefinition"/>s, <see cref="GenericParameter"/>s (returning an <see cref="OpenTypeParameterRef"/>),
        /// <see cref="TypeReference"/>s (resolving them to a <see cref="TypeDefinition"/>), or arrays of any of those.  For a known <see cref="TypeDefinition"/>,
        /// you may use a 'new TypeRef()' constructor for efficiency.
        /// </summary>
        public static TypeRefBase Create(TypeReference typeReference, params Expression[] typeArguments)
        {
            // No need to check 'typeArguments' for null, because a different constructor would have been called
            return Create(typeReference, false, typeArguments);
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="TypeReference"/>.
        /// This factory method handles <see cref="TypeDefinition"/>s, <see cref="GenericParameter"/>s (returning an <see cref="OpenTypeParameterRef"/>),
        /// <see cref="TypeReference"/>s (resolving them to a <see cref="TypeDefinition"/>), or arrays of any of those.  For a known <see cref="TypeDefinition"/>,
        /// you may use a 'new TypeRef()' constructor for efficiency.
        /// </summary>
        public static TypeRefBase Create(TypeReference typeReference, bool isFirstOnLine, params int[] arrayRanks)
        {
            // Convert the array of ranks to a List so we can use the factory method above.
            return Create(typeReference, isFirstOnLine, null, new List<int>(arrayRanks));
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="TypeReference"/>.
        /// This factory method handles <see cref="TypeDefinition"/>s, <see cref="GenericParameter"/>s (returning an <see cref="OpenTypeParameterRef"/>),
        /// <see cref="TypeReference"/>s (resolving them to a <see cref="TypeDefinition"/>), or arrays of any of those.  For a known <see cref="TypeDefinition"/>,
        /// you may use a 'new TypeRef()' constructor for efficiency.
        /// </summary>
        public static TypeRefBase Create(TypeReference typeReference, params int[] arrayRanks)
        {
            return Create(typeReference, false, arrayRanks);
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="GenericParameter"/> (will return a derived <see cref="OpenTypeParameterRef"/>).
        /// </summary>
        public static TypeParameterRef Create(GenericParameter genericParameter, bool isFirstOnLine, List<int> arrayRanks)
        {
            return new TypeParameterRef(genericParameter, isFirstOnLine, arrayRanks);
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="GenericParameter"/> (will return a derived <see cref="OpenTypeParameterRef"/>).
        /// </summary>
        public static TypeParameterRef Create(GenericParameter genericParameter, bool isFirstOnLine)
        {
            return new TypeParameterRef(genericParameter, isFirstOnLine);
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="GenericParameter"/> (will return a derived <see cref="OpenTypeParameterRef"/>).
        /// </summary>
        public static TypeParameterRef Create(GenericParameter genericParameter)
        {
            return new TypeParameterRef(genericParameter, false);
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="GenericParameter"/> (will return a derived <see cref="OpenTypeParameterRef"/>).
        /// </summary>
        public static TypeParameterRef Create(GenericParameter genericParameter, List<int> arrayRanks)
        {
            return Create(genericParameter, false, arrayRanks);
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="GenericParameter"/> (will return a derived <see cref="OpenTypeParameterRef"/>).
        /// </summary>
        public static TypeParameterRef Create(GenericParameter genericParameter, bool isFirstOnLine, params int[] arrayRanks)
        {
            return Create(genericParameter, isFirstOnLine, new List<int>(arrayRanks));
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="GenericParameter"/> (will return a derived <see cref="OpenTypeParameterRef"/>).
        /// </summary>
        public static TypeParameterRef Create(GenericParameter genericParameter, params int[] arrayRanks)
        {
            return Create(genericParameter, false, arrayRanks);
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// Use this factory method if the Type might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>) or
        /// an array of one of those, otherwise you may use a 'new TypeRef()' constructor for efficiency.
        /// </summary>
        public static TypeRef Create(Type type, bool isFirstOnLine, ChildList<Expression> typeArguments, List<int> arrayRanks)
        {
            if (type == null)
                return null;

            // If the type is an array, and no array ranks were specified, use the existing array ranks (otherwise override them)
            if (type.IsArray)
            {
                bool useExistingRanks = (arrayRanks == null);
                if (useExistingRanks)
                    arrayRanks = new List<int>();
                do
                {
                    if (useExistingRanks)
                        arrayRanks.Add(type.GetArrayRank());
                    type = type.GetElementType();
                }
                while (type.IsArray);
            }

            // Dereference (remove the trailing '&') if it's a reference type
            if (type.IsByRef)
                type = type.GetElementType();

            // Create a reference of the appropriate type
            if (type.IsGenericParameter)
                return new TypeParameterRef(type, isFirstOnLine, arrayRanks);  // Ignore any type arguments in this case
            if (type.IsGenericType)
            {
                // Use any type arguments in the type if none were specified
                if (typeArguments == null)
                    typeArguments = DefaultTypeArguments(type, null);
            }
            return new TypeRef(type, isFirstOnLine, typeArguments, arrayRanks);
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// Use this factory method if the Type might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>) or
        /// an array of one of those, otherwise you may use a 'new TypeRef()' constructor for efficiency.
        /// </summary>
        public static TypeRef Create(Type type, bool isFirstOnLine, ChildList<Expression> typeArguments)
        {
            return Create(type, isFirstOnLine, typeArguments, null);
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// Use this factory method if the Type might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>) or
        /// an array of one of those, otherwise you may use a 'new TypeRef()' constructor for efficiency.
        /// </summary>
        public static TypeRef Create(Type type, bool isFirstOnLine)
        {
            return Create(type, isFirstOnLine, (ChildList<Expression>)null, null);
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// Use this factory method if the Type might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>) or
        /// an array of one of those, otherwise you may use a 'new TypeRef()' constructor for efficiency.
        /// </summary>
        public static TypeRef Create(Type type)
        {
            return Create(type, false, (ChildList<Expression>)null, null);
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// Use this factory method if the Type might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>) or
        /// an array of one of those, otherwise you may use a 'new TypeRef()' constructor for
        /// efficiency.
        /// </summary>
        public static TypeRef Create(Type type, ChildList<Expression> typeArguments, List<int> arrayRanks)
        {
            return Create(type, false, typeArguments, arrayRanks);
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// Use this factory method if the Type might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>) or
        /// an array of one of those, otherwise you may use a 'new TypeRef()' constructor for
        /// efficiency.
        /// </summary>
        public static TypeRef Create(Type type, ChildList<Expression> typeArguments)
        {
            return Create(type, false, typeArguments, null);
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// Use this factory method if the Type might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>) or
        /// an array of one of those, otherwise you may use a 'new TypeRef()' constructor for
        /// efficiency.
        /// </summary>
        public static TypeRef Create(Type type, bool isFirstOnLine, params Expression[] typeArguments)
        {
            // No need to check 'typeArguments' for null, because a different constructor would have been called.
            // Convert the array of expressions to a ChildList so we can use the factory method above.
            return Create(type, isFirstOnLine, new ChildList<Expression>(typeArguments));
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// Use this factory method if the Type might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>) or
        /// an array of one of those, otherwise you may use a 'new TypeRef()' constructor for
        /// efficiency.
        /// </summary>
        public static TypeRef Create(Type type, params Expression[] typeArguments)
        {
            // No need to check 'typeArguments' for null, because a different constructor would have been called
            return Create(type, false, typeArguments);
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// Use this factory method if the Type might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>) or
        /// an array of one of those, otherwise you may use a 'new TypeRef()' constructor for
        /// efficiency.
        /// </summary>
        public static TypeRef Create(Type type, bool isFirstOnLine, params int[] arrayRanks)
        {
            // Convert the array of ranks to a List so we can use the factory method above.
            return Create(type, isFirstOnLine, null, new List<int>(arrayRanks));
        }

        /// <summary>
        /// Construct a <see cref="TypeRef"/> from a <see cref="Type"/>.
        /// Use this factory method if the Type might be a generic parameter (requiring an <see cref="OpenTypeParameterRef"/>/<see cref="TypeParameterRef"/>) or
        /// an array of one of those, otherwise you may use a 'new TypeRef()' constructor for
        /// efficiency.
        /// </summary>
        public static TypeRef Create(Type type, params int[] arrayRanks)
        {
            return Create(type, false, arrayRanks);
        }

        /// <summary>
        /// Create a <see cref="TypeRef"/> to a nullable version of the specified type expression.
        /// </summary>
        public static TypeRef CreateNullable(Expression typeExpression, bool isFirstOnLine, List<int> arrayRanks)
        {
            object nullableRef = Nullable1Ref.Reference;
            if (nullableRef is TypeDefinition)
                return new TypeRef((TypeDefinition)nullableRef, isFirstOnLine, typeExpression) { ArrayRanks = arrayRanks };
            return new TypeRef((Type)nullableRef, isFirstOnLine, typeExpression) { ArrayRanks = arrayRanks };
        }

        /// <summary>
        /// Create a <see cref="TypeRef"/> to a nullable version of the specified type expression.
        /// </summary>
        public static TypeRef CreateNullable(Expression typeExpression, List<int> arrayRanks)
        {
            return CreateNullable(typeExpression, false, arrayRanks);
        }

        /// <summary>
        /// Create a <see cref="TypeRef"/> to a nullable version of the specified type expression.
        /// </summary>
        public static TypeRef CreateNullable(Expression typeExpression, bool isFirstOnLine)
        {
            return CreateNullable(typeExpression, isFirstOnLine, null);
        }

        /// <summary>
        /// Create a <see cref="TypeRef"/> to a nullable version of the specified type expression.
        /// </summary>
        public static TypeRef CreateNullable(Expression typeExpression)
        {
            return CreateNullable(typeExpression, false, null);
        }

        /// <summary>
        /// Create a type expression for the specified <see cref="TypeDefinition"/>, handling nested types.
        /// </summary>
        public static Expression CreateNested(TypeDefinition typeDefinition)
        {
            if (typeDefinition.IsNested)
                return new Dot(CreateNested(typeDefinition.DeclaringType), Create(typeDefinition));
            return Create(typeDefinition);
        }

        /// <summary>
        /// Create a type expression for the specified <see cref="Type"/>, handling nested types.
        /// </summary>
        public static Expression CreateNested(Type type)
        {
            if (type.IsNested)
                return new Dot(CreateNested(type.DeclaringType), Create(type));
            return Create(type);
        }

        /// <summary>
        /// Find a type in the specified <see cref="Namespace"/> with the specified name.
        /// </summary>
        /// <returns>A <see cref="TypeRef"/> to the type, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
        public static TypeRefBase Find(Namespace @namespace, string typeName, bool isFirstOnLine)
        {
            return CreateTypeRef(@namespace.Find(typeName), typeName, isFirstOnLine);
        }

        /// <summary>
        /// Find a type in the specified <see cref="Namespace"/> with the specified name.
        /// </summary>
        /// <returns>A <see cref="TypeRef"/> to the type, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
        public static TypeRefBase Find(Namespace @namespace, string typeName)
        {
            return CreateTypeRef(@namespace.Find(typeName), typeName, false);
        }

        /// <summary>
        /// Find a type in the specified type or namespace <see cref="Alias"/> with the specified name.
        /// </summary>
        /// <returns>A <see cref="NamespaceRef"/>, <see cref="TypeRef"/>, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
        public static TypeRefBase Find(Alias alias, string typeName, bool isFirstOnLine)
        {
            // We need to handle Namespace and Alias separately instead of using INamespace in order
            // to avoid ambiguity between INamespace and ITypeDecl when an Alias is passed in.
            return CreateTypeRef(alias.Find(typeName), typeName, isFirstOnLine);
        }

        /// <summary>
        /// Find a type in the specified type or namespace <see cref="Alias"/> with the specified name.
        /// </summary>
        /// <returns>A <see cref="NamespaceRef"/>, <see cref="TypeRef"/>, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
        public static TypeRefBase Find(Alias alias, string typeName)
        {
            // We need to handle Namespace and Alias separately instead of using INamespace in order
            // to avoid ambiguity between INamespace and ITypeDecl when an Alias is passed in.
            return CreateTypeRef(alias.Find(typeName), typeName, false);
        }

        /// <summary>
        /// Find a type in the specified <see cref="NamespaceRef"/> or <see cref="TypeRefBase"/> with the specified name.
        /// </summary>
        /// <returns>A <see cref="TypeRef"/> to the type, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
        public static TypeRefBase Find(SymbolicRef symbolicRef, string typeName, bool isFirstOnLine)
        {
            if (symbolicRef is NamespaceRef)
                return CreateTypeRef(((NamespaceRef)symbolicRef).Namespace.Find(typeName), typeName, isFirstOnLine);
            if (symbolicRef is TypeRef)
            {
                TypeRef typeRef = ((TypeRef)symbolicRef).GetNestedType(typeName);
                if (typeRef != null)
                {
                    typeRef.IsFirstOnLine = isFirstOnLine;
                    return typeRef;
                }
            }
            return new UnresolvedRef(typeName, isFirstOnLine, ResolveCategory.Type);
        }

        /// <summary>
        /// Find a type in the specified <see cref="NamespaceRef"/> or <see cref="TypeRefBase"/> with the specified name.
        /// </summary>
        /// <returns>A <see cref="TypeRef"/> to the type, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
        public static TypeRefBase Find(SymbolicRef symbolicRef, string typeName)
        {
            return Find(symbolicRef, typeName, false);
        }

        protected internal static TypeRefBase CreateTypeRef(object obj, string name, bool isFirstOnLine)
        {
            if (obj is TypeDecl)
                return new TypeRef((TypeDecl)obj, isFirstOnLine);
            if (obj is TypeDefinition)
                return new TypeRef((TypeDefinition)obj, isFirstOnLine);
            if (obj is Type)
                return new TypeRef((Type)obj, isFirstOnLine);
            return new UnresolvedRef(name, isFirstOnLine, ResolveCategory.NamespaceOrType);
        }

        /// <summary>
        /// Find a nested type in the specified <see cref="TypeDecl"/> with the specified name.
        /// </summary>
        /// <returns>A <see cref="TypeRef"/> to the type, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
        public static TypeRefBase Find(TypeDecl typeDecl, string name, bool isFirstOnLine)
        {
            if (typeDecl != null)
            {
                TypeRef typeRef = typeDecl.GetNestedType(name);
                if (typeRef != null)
                {
                    typeRef.IsFirstOnLine = isFirstOnLine;
                    return typeRef;
                }
            }
            return new UnresolvedRef(name, isFirstOnLine, ResolveCategory.Type);
        }

        /// <summary>
        /// Find a nested type in the specified <see cref="TypeDecl"/> with the specified name.
        /// </summary>
        /// <returns>A <see cref="TypeRef"/> to the type, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
        public static TypeRefBase Find(TypeDecl typeDecl, string name)
        {
            return Find(typeDecl, name, false);
        }

        /// <summary>
        /// Find a nested type in the specified <see cref="Type"/> with the specified name.
        /// </summary>
        /// <returns>A <see cref="TypeRef"/> to the type, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
        public static TypeRefBase Find(Type type, string name, bool isFirstOnLine)
        {
            if (type != null)
            {
                type = type.GetNestedType(name);
                if (type != null)
                    return new TypeRef(type, isFirstOnLine);
            }
            return new UnresolvedRef(name, isFirstOnLine, ResolveCategory.Type);
        }

        /// <summary>
        /// Find a nested type in the specified <see cref="Type"/> with the specified name.
        /// </summary>
        /// <returns>A <see cref="TypeRef"/> to the type, or an <see cref="UnresolvedRef"/> if no match was found.</returns>
        public static TypeRefBase Find(Type type, string name)
        {
            return Find(type, name, false);
        }

        /// <summary>
        /// Get all (non-static) constructors for the specified code object.
        /// </summary>
        public static NamedCodeObjectGroup GetConstructors(object obj, bool currentPartOnly)
        {
            if (obj is ITypeDecl)
                return ((ITypeDecl)obj).GetConstructors(currentPartOnly);
            if (obj is TypeDefinition)
            {
                TypeDefinition typeDefinition = (TypeDefinition)obj;
                if (TypeDefinitionUtil.IsDelegateType(typeDefinition))
                {
                    // Delegates have a constructor that takes an object and an IntPtr that is used internally
                    // by the compiler during code generation.  We have to create a dummy constructor that will
                    // allow a MethodRef to be passed to it, in order to make the C# syntax work.  The Parent
                    // can't be set to the TypeDefinition, but the TypeDefinition can be acquired from the parameter's type.
                    ConstructorDecl constructorDecl =
                        new ConstructorDecl(new[] { new ParameterDecl(DelegateDecl.DelegateConstructorParameterName, new TypeRef(typeDefinition)) }) { IsGenerated = true, Name = TypeDefinitionUtil.NonGenericName(typeDefinition) };
                    return new NamedCodeObjectGroup(constructorDecl);
                }
                // Find both public and protected instance constructors
                return new NamedCodeObjectGroup(TypeDefinitionUtil.GetConstructors(typeDefinition, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance));
            }
            if (obj is Type)
            {
                Type type = (Type)obj;
                if (TypeUtil.IsDelegateType(type))
                {
                    // Delegates have a constructor that takes an object and an IntPtr that is used internally
                    // by the compiler during code generation.  We have to create a dummy constructor that will
                    // allow a MethodRef to be passed to it, in order to make the C# syntax work.  The Parent
                    // can't be set to the Type, but the Type can be acquired from the parameter's type.
                    ConstructorDecl constructorDecl =
                        new ConstructorDecl(new[] { new ParameterDecl(DelegateDecl.DelegateConstructorParameterName, new TypeRef(type)) }) { IsGenerated = true, Name = TypeUtil.NonGenericName(type) };
                    return new NamedCodeObjectGroup(constructorDecl);
                }
                // Find both public and protected instance constructors
                return new NamedCodeObjectGroup(type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance));
            }
            return null;
        }

        /// <summary>
        /// Get all (non-static) constructors for the specified code object.
        /// </summary>
        public static NamedCodeObjectGroup GetConstructors(object obj)
        {
            return GetConstructors(obj, false);
        }

        /// <summary>
        /// Change the type of the specified constant to the specified type if possible.
        /// </summary>
        public static object ChangeTypeOfConstant(object constantValue, TypeRefBase typeRefBase)
        {
            if (constantValue != null && typeRefBase != null)
            {
                bool isNullableType = false;
                if (typeRefBase.IsNullableType)
                {
                    isNullableType = true;
                    typeRefBase = typeRefBase.TypeArguments[0].EvaluateType();
                }
                object reference = typeRefBase.Reference;

                Type constantType = (reference is TypeDefinition ? GetEquivalentType((TypeDefinition)reference) : reference as Type);
                if (isNullableType)
                    constantType = typeof(Nullable<>).MakeGenericType(constantType);
                if (constantType != null && constantValue.GetType() != constantType)
                    constantValue = TypeUtil.ChangeType(constantValue, constantType);
            }
            return constantValue;
        }

        /// <summary>
        /// Change the type of the specified constant to the specified type if possible.
        /// </summary>
        public static object ChangeTypeOfConstant(object constantValue, TypeReference typeReference)
        {
            if (constantValue != null && typeReference != null)
            {
                Type constantType = GetEquivalentType(typeReference);
                if (constantType != null && constantValue.GetType() != constantType)
                    constantValue = TypeUtil.ChangeType(constantValue, constantType);
            }
            return constantValue;
        }

        #endregion

        #region /* METHODS */

        /// <summary>
        /// Get the base type of the referenced type.
        /// </summary>
        public TypeRefBase GetBaseType()
        {
            if (HasArrayRanks) return ArrayRef;
            TypeRefBase baseTypeRef = null;
            object reference = GetReferencedType();
            if (reference is ITypeDecl)
                baseTypeRef = ((ITypeDecl)reference).GetBaseType();
            else if (reference is TypeDefinition)
                baseTypeRef = Create(((TypeDefinition)reference).BaseType);
            else if (reference is Type)
                baseTypeRef = Create(((Type)reference).BaseType);
            if (baseTypeRef != null)
                baseTypeRef = baseTypeRef.EvaluateTypeArgumentTypes(this);
            return baseTypeRef;
        }

        /// <summary>
        /// Get the non-static constructor for the referenced type.
        /// </summary>
        public ConstructorRef GetConstructor(params TypeRefBase[] parameterTypes)
        {
            if (HasArrayRanks)
                return ArrayRef.GetConstructor(parameterTypes);
            object reference = GetReferencedType();
            if (reference is ITypeDecl)
                return ((ITypeDecl)reference).GetConstructor(parameterTypes);
            if (reference is TypeDefinition)
            {
                TypeReference[] typeReferences = GetTypeRefsAsTypeReferences(parameterTypes);
                if (typeReferences != null)
                {
                    MethodDefinition constructorDefinition = TypeDefinitionUtil.GetConstructor((TypeDefinition)reference, typeReferences);
                    if (constructorDefinition != null)
                        return new ConstructorRef(constructorDefinition);
                }
            }
            if (reference is Type)
            {
                Type[] types = GetTypeRefsAsTypes(parameterTypes);
                if (types != null)
                {
                    ConstructorInfo constructorInfo = ((Type)reference).GetConstructor(types);
                    if (constructorInfo != null)
                        return new ConstructorRef(constructorInfo);
                }
            }
            return null;
        }

        /// <summary>
        /// Get all (non-static) constructors for the referenced type.
        /// </summary>
        public NamedCodeObjectGroup GetConstructors(bool currentPartOnly)
        {
            return GetConstructors(Reference, currentPartOnly);
        }

        /// <summary>
        /// Get all (non-static) constructors for the referenced type.
        /// </summary>
        public NamedCodeObjectGroup GetConstructors()
        {
            return GetConstructors(Reference, false);
        }

        /// <summary>
        /// Get the method with the specified name, binding flags, and parameter types.
        /// </summary>
        public MethodRef GetMethod(string name, BindingFlags bindingFlags, params TypeRefBase[] parameterTypes)
        {
            if (HasArrayRanks)
                return ArrayRef.GetMethod(name, bindingFlags, parameterTypes);
            object reference = GetReferencedType();
            if (reference is ITypeDecl)
                return ((ITypeDecl)reference).GetMethod(name, parameterTypes);
            if (reference is TypeDefinition)
            {
                TypeReference[] typeReferences = GetTypeRefsAsTypeReferences(parameterTypes);
                if (typeReferences != null)
                {
                    MethodDefinition methodDefinition = TypeDefinitionUtil.GetMethod((TypeDefinition)reference, name, bindingFlags, typeReferences);
                    if (methodDefinition != null)
                        return new MethodRef(methodDefinition);
                }
            }
            if (reference is Type)
            {
                Type[] types = GetTypeRefsAsTypes(parameterTypes);
                if (types != null)
                {
                    MethodInfo methodInfo = TypeUtil.GetMethod((Type)reference, name, bindingFlags, types);
                    if (methodInfo != null)
                        return new MethodRef(methodInfo);
                }
            }
            return null;
        }

        /// <summary>
        /// Get the method with the specified name and parameter types.
        /// </summary>
        public MethodRef GetMethod(string name, params TypeRefBase[] parameterTypes)
        {
            return GetMethod(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, parameterTypes);
        }

        /// <summary>
        /// Convert a TypeRefBase[] to a TypeReference[].  Returns null if any conversion fails.
        /// </summary>
        private static TypeReference[] GetTypeRefsAsTypeReferences(TypeRefBase[] typeRefs)
        {
            int count = (typeRefs != null ? typeRefs.Length : 0);
            TypeReference[] types = new TypeReference[count];
            for (int i = 0; i < count; ++i)
            {
                object reference = typeRefs[i].GetReferencedType();
                if (reference is TypeReference)
                    types[i] = (TypeReference)reference;
                else if (reference is Type)
                {
                    // Try to find the equivalent TypeReference for the Type
                    TypeDefinition typeDefinition;
                    if (TypeNameToTypeDefinition.TryGetValue(MemberInfoUtil.GetFullName((Type)reference), out typeDefinition))
                        types[i] = typeDefinition;
                    else
                        return null;
                }
                else
                    return null;
            }
            return types;
        }

        /// <summary>
        /// Convert a TypeRefBase[] to a Type[].  Returns null if any conversion fails.
        /// </summary>
        private static Type[] GetTypeRefsAsTypes(TypeRefBase[] typeRefs)
        {
            int count = (typeRefs != null ? typeRefs.Length : 0);
            Type[] types = new Type[count];
            for (int i = 0; i < count; ++i)
            {
                object reference = typeRefs[i].GetReferencedType();
                if (reference is Type)
                    types[i] = (Type)reference;
                else
                    return null;
            }
            return types;
        }

        /// <summary>
        /// Get all methods with the specified name.
        /// </summary>
        public void GetMethods(string name, bool searchBaseClasses, NamedCodeObjectGroup results)
        {
            if (HasArrayRanks)
                ArrayRef.GetMethods(name, searchBaseClasses, results);
            else
            {
                object reference = GetReferencedType();
                if (reference is ITypeDecl)
                    ((ITypeDecl)reference).GetMethods(name, searchBaseClasses, results);
                else if (reference is TypeDefinition)
                    GetMethods((TypeDefinition)reference, name, searchBaseClasses, results);
                else if (reference is Type)
                    GetMethods((Type)reference, name, searchBaseClasses, results);
            }
        }

        /// <summary>
        /// Get all methods with the specified name.
        /// </summary>
        /// <param name="name">The method name.</param>
        /// <param name="searchBaseClasses">Pass <c>false</c> to NOT search base classes.</param>
        public List<MethodRef> GetMethods(string name, bool searchBaseClasses)
        {
            NamedCodeObjectGroup results = new NamedCodeObjectGroup();
            GetMethods(name, searchBaseClasses, results);
            return MethodRef.MethodRefsFromGroup(results);
        }

        /// <summary>
        /// Get all methods with the specified name.
        /// </summary>
        /// <param name="name">The method name.</param>
        public List<MethodRef> GetMethods(string name)
        {
            return GetMethods(name, true);
        }

        private static void GetMethods(TypeDefinition typeDefinition, string name, bool searchBaseClasses, NamedCodeObjectGroup results)
        {
            // Get all methods with the specified name
            results.Add(Enumerable.Where(typeDefinition.Methods, delegate(MethodDefinition method) { return method.Name == name; }));

            if (searchBaseClasses)
            {
                TypeReference baseType = typeDefinition.BaseType;
                if (baseType != null)
                {
                    TypeDefinition baseDefinition = null;
                    try { baseDefinition = baseType.Resolve(); }
                    catch { }
                    if (baseDefinition != null)
                        GetMethods(baseDefinition, name, true, results);
                }
            }

            // If we're searching an interface, we have to manually search base interfaces
            if (typeDefinition.IsInterface)
            {
                foreach (TypeReference interfaceReference in typeDefinition.Interfaces)
                {
                    TypeDefinition interfaceDefinition = null;
                    try { interfaceDefinition = interfaceReference.Resolve(); }
                    catch { }
                    if (interfaceDefinition != null)
                        results.Add(Enumerable.Where(interfaceDefinition.Methods, delegate(MethodDefinition method) { return method.Name == name; }));
                }
            }
        }

        private static void GetMethods(Type type, string name, bool searchBaseClasses, NamedCodeObjectGroup results)
        {
            try
            {
                // Get all methods with the specified name
                MemberInfo[] members = type.GetMember(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance
                    | (searchBaseClasses ? BindingFlags.FlattenHierarchy : BindingFlags.DeclaredOnly));
                foreach (MemberInfo memberInfo in members)
                {
                    if (memberInfo is MethodBase)
                        results.Add(memberInfo);
                }

                // If we're searching an interface, we have to manually search base interfaces
                if (type.IsInterface)
                {
                    foreach (Type interfaceType in type.GetInterfaces())
                    {
                        members = interfaceType.GetMember(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);
                        foreach (MemberInfo memberInfo in members)
                        {
                            if (memberInfo is MethodBase)
                                results.Add(memberInfo);
                        }
                    }
                }
            }
            catch
            {
                // Ignore any exceptions - can be caused by missing dependent assemblies
            }
        }

        /// <summary>
        /// Get the property with the specified name.
        /// </summary>
        public PropertyRef GetProperty(string name)
        {
            if (HasArrayRanks)
                return ArrayRef.GetProperty(name);
            object reference = GetReferencedType();
            if (reference is ITypeDecl)
                return ((ITypeDecl)reference).GetProperty(name);
            if (reference is TypeDefinition)
            {
                PropertyDefinition propertyDefinition = TypeDefinitionUtil.GetProperty((TypeDefinition)reference, name);
                if (propertyDefinition != null)
                    return new PropertyRef(propertyDefinition);
            }
            if (reference is Type)
            {
                PropertyInfo propertyInfo = TypeUtil.GetProperty((Type)reference, name);
                if (propertyInfo != null)
                    return new PropertyRef(propertyInfo);
            }
            return null;
        }

        /// <summary>
        /// Get the field with the specified name.
        /// </summary>
        public FieldRef GetField(string name)
        {
            object reference = GetReferencedType();
            if (reference is ITypeDecl)
                return ((ITypeDecl)reference).GetField(name);
            if (reference is TypeDefinition)
            {
                FieldDefinition fieldDefinition = Enumerable.FirstOrDefault(((TypeDefinition)reference).Fields, delegate(FieldDefinition field) { return field.Name == name; });
                if (fieldDefinition != null)
                    return new FieldRef(fieldDefinition);
            }
            if (reference is Type)
            {
                FieldInfo fieldInfo = ((Type)reference).GetField(name);
                if (fieldInfo != null)
                    return new FieldRef(fieldInfo);
            }
            return null;
        }

        /// <summary>
        /// Get the nested type with the specified name.
        /// </summary>
        public TypeRef GetNestedType(string name)
        {
            object reference = GetReferencedType();
            if (reference is ITypeDecl)
                return ((ITypeDecl)reference).GetNestedType(name);
            if (reference is TypeDefinition)
            {
                TypeDefinition typeDefinition = Enumerable.FirstOrDefault(((TypeDefinition)reference).NestedTypes, delegate(TypeDefinition type) { return type.Name == name; });
                if (typeDefinition != null)
                    return new TypeRef(typeDefinition);
            }
            if (reference is Type)
            {
                Type type = ((Type)reference).GetNestedType(name);
                if (type != null)
                    return new TypeRef(type);
            }
            return null;
        }

        /// <summary>
        /// Get the delegate parameters if the expression evaluates to a delegate type.
        /// </summary>
        public override ICollection GetDelegateParameters()
        {
            object reference = GetReferencedType();
            if (reference is ITypeDecl)
                return ((ITypeDecl)reference).GetDelegateParameters();
            if (reference is TypeReference)
                return TypeDefinitionUtil.GetDelegateParameters((TypeReference)reference);
            if (reference is Type)
                return TypeUtil.GetDelegateParameters((Type)reference);
            // It would be nice to replace any type parameters in the types of the parameters with type
            // arguments if possible as in GetDelegateReturnType() below, but this is not feasible since
            // we can't modify the types of the parameter objects, and we need the parameter objects in
            // order to check ref/out flags.  The only way to do this would be to allocate new collections
            // of fake ParameterDecl objects with evaluated types, but that gets really messy.  Instead,
            // callers of this method have to worry about evaluating any type parameters.
            return null;
        }

        /// <summary>
        /// Get the delegate return type if the expression evaluates to a delegate type.
        /// </summary>
        public override TypeRefBase GetDelegateReturnType()
        {
            TypeRefBase returnTypeRef = null;
            object reference = GetReferencedType();
            if (reference is ITypeDecl)
                returnTypeRef = ((ITypeDecl)reference).GetDelegateReturnType();
            else if (reference is TypeDefinition)
            {
                TypeDefinition typeReference = (TypeDefinition)reference;
                if (TypeDefinitionUtil.IsDelegateType(typeReference))
                {
                    MethodDefinition delegateInvokeMethodDefinition = TypeDefinitionUtil.GetInvokeMethod(typeReference);
                    if (delegateInvokeMethodDefinition != null)
                    {
                        TypeReference returnType = delegateInvokeMethodDefinition.ReturnType;
                        returnTypeRef = Create(returnType);
                    }
                }
            }
            else if (reference is Type)
            {
                Type type = (Type)reference;
                if (TypeUtil.IsDelegateType(type))
                {
                    MethodInfo delegateInvokeMethodInfo = TypeUtil.GetInvokeMethod(type);
                    if (delegateInvokeMethodInfo != null)
                    {
                        Type returnType = delegateInvokeMethodInfo.ReturnType;
                        returnTypeRef = Create(returnType);
                    }
                }
            }
            // Replace any type parameters in the result with type arguments if possible
            if (returnTypeRef != null && HasTypeArguments)
                returnTypeRef = returnTypeRef.EvaluateTypeArgumentTypes(this);
            return returnTypeRef;
        }

        /// <summary>
        /// Get the number of specified type arguments.
        /// </summary>
        public int GetLocalTypeArgumentCount()
        {
            int count = 0;
            object reference = GetReferencedType();
            if (reference is ITypeDecl)
                count = ((ITypeDecl)reference).TypeParameterCount;
            else if (reference is TypeDefinition)
                count = TypeDefinitionUtil.GetLocalGenericArgumentCount((TypeDefinition)reference);
            else if (reference is Type)
                count = TypeUtil.GetLocalGenericArgumentCount((Type)reference);
            return count;
        }

        /// <summary>
        /// Get the declared type parameters (if any) of the referenced type as type arguments.
        /// </summary>
        public ChildList<Expression> GetTypeParametersAsArguments()
        {
            ChildList<Expression> typeArguments = null;
            object reference = GetReferencedType();
            if (reference is TypeDecl)
            {
                ChildList<TypeParameter> typeParameters = ((TypeDecl)reference).TypeParameters;
                if (typeParameters != null)
                {
                    typeArguments = new ChildList<Expression>(typeParameters.Count);
                    foreach (TypeParameter typeParameter in typeParameters)
                        typeArguments.Add(typeParameter.CreateRef());
                }
            }
            else if (reference is TypeDefinition)
            {
                IEnumerable<GenericParameter> genericArguments = TypeDefinitionUtil.GetLocalGenericArguments((TypeDefinition)reference);
                if (genericArguments != null)
                {
                    typeArguments = new ChildList<Expression>();
                    foreach (GenericParameter genericArgument in genericArguments)
                        typeArguments.Add(Create(genericArgument));
                }
            }
            else if (reference is Type)
            {
                Type[] genericArguments = TypeUtil.GetLocalGenericArguments((Type)reference);
                if (genericArguments.Length > 0)
                {
                    typeArguments = new ChildList<Expression>(genericArguments.Length);
                    foreach (Type genericArgument in genericArguments)
                        typeArguments.Add(Create(genericArgument));
                }
            }
            else if (reference is Alias)
            {
                TypeRef aliasedTypeRef = ((Alias)reference).Type;
                if (aliasedTypeRef != null)
                    typeArguments = aliasedTypeRef.GetTypeParametersAsArguments();
            }
            return typeArguments;
        }

        /// <summary>
        /// Get the <see cref="TypeCode"/> of the referenced type.
        /// </summary>
        public TypeCode GetTypeCode()
        {
            object reference = GetReferencedType();
            if (reference is ITypeDecl)
            {
                TypeCode typeCode;
                if (TypeNameToTypeCodeMap.TryGetValue(((ITypeDecl)reference).Name, out typeCode) && ((ITypeDecl)reference).GetNamespace().Name == "System")
                    return typeCode;
            }
            else if (reference is TypeDefinition)
            {
                TypeCode typeCode;
                if (TypeNameToTypeCodeMap.TryGetValue(((TypeDefinition)reference).Name, out typeCode) && ((TypeDefinition)reference).Namespace == "System")
                    return typeCode;
            }
            else if (reference is Type)
                return Type.GetTypeCode((Type)reference);
            return TypeCode.Object;
        }

        /// <summary>
        /// Determine if the current reference refers to the same code object as the specified reference.
        /// </summary>
        public override bool IsSameRef(SymbolicRef symbolicRef)
        {
            // Comparing the type name and namespace is the most efficient method.
            // Just comparing the type objects wouldn't always work - such as when types are present both in an assembly
            // reference, and also as CodeDOM objects (either in the current project, or a referenced project), which can
            // occur if one or both types are in a project with assembly references instead of project references to a type
            // that is defined in the current solution, which isn't uncommon (it will occur in "master" solutions that include
            // projects that are also used in other solutions, and also if a project in the solution uses a non-supported
            // language and so is referenced by its assembly.  It would also fail in the case that both types are partial types
            // of the same type declaration (meaning two parts of an ITypeDecl in the same project).  Finally, it would fail if
            // the types are the same type from assemblies with different versions, such as from different versions of the .NET
            // framework, which can easily occur if different projects in the same solution target different framework versions.
            TypeRef typeRef = (symbolicRef is AliasRef ? ((AliasRef)symbolicRef).Type : symbolicRef as TypeRef);
            return (typeRef != null && Name == typeRef.Name && NamespaceName == typeRef.NamespaceName
                && HasSameTypeArguments(typeRef) && HasSameArrayRanks(typeRef));
        }

        /// <summary>
        /// Determine if this <see cref="TypeRef"/> has the same type arguments as the specified <see cref="TypeRef"/>.
        /// </summary>
        protected bool HasSameTypeArguments(TypeRef typeRef)
        {
            ChildList<Expression> typeArguments1 = TypeArguments;
            ChildList<Expression> typeArguments2 = typeRef.TypeArguments;
            int typeArgumentCount = (typeArguments1 != null ? typeArguments1.Count : 0);
            if (typeArgumentCount != (typeArguments2 != null ? typeArguments2.Count : 0))
                return false;
            if (typeArgumentCount > 0)
            {
                for (int i = 0; i < typeArgumentCount; ++i)
                {
                    Expression typeArg1 = typeArguments1[i];
                    Expression typeArg2 = typeArguments2[i];
                    if (typeArg1 == null && typeArg2 == null)
                        continue;
                    if (typeArg1 == null || typeArg2 == null)
                        return false;
                    TypeRefBase typeArgRef1 = typeArg1.EvaluateType();
                    TypeRefBase typeArgRef2 = typeArg2.EvaluateType();
                    if (typeArgRef1 == null || typeArgRef2 == null)
                        return false;
                    if (typeArgRef1.ImplicitIdentityConversionExists(typeArgRef2))
                        continue;
                    return false;
                }
            }
            return true;
        }

        /// <summary>
        /// Determine if this <see cref="TypeRef"/> has the same array ranks as the specified <see cref="TypeRef"/>.
        /// </summary>
        protected bool HasSameArrayRanks(TypeRef typeRef)
        {
            int arrayRanksCount = (ArrayRanks != null ? ArrayRanks.Count : 0);
            if (arrayRanksCount != (typeRef.ArrayRanks != null ? typeRef.ArrayRanks.Count : 0))
                return false;
            if (arrayRanksCount > 0 && !CollectionUtil.CompareList(ArrayRanks, typeRef.ArrayRanks))
                return false;
            return true;
        }

        /// <summary>
        /// Calculate a hash code for the referenced object which is the same for all references where IsSameRef() is true.
        /// </summary>
        /// <remarks>
        /// We don't want to override GetHashCode(), because we want all TypeRefs to have unique hashes so they can be
        /// used as dictionary keys.  However, we also sometimes want hashes to be the same if IsSameRef() is true - this
        /// method allows for that.
        /// </remarks>
        public override int GetIsSameRefHashCode()
        {
            // Make the hash codes as unique as possible while still ensuring that they are identical
            // for any objects for which IsSameRef() returns true.
            int hashCode = Name.GetHashCode();
            string namespaceName = NamespaceName;
            if (namespaceName != null) hashCode ^= namespaceName.GetHashCode();
            List<int> arrayRanks = ArrayRanks;
            if (arrayRanks != null)
            {
                foreach (int rank in arrayRanks)
                    hashCode = (hashCode << 1) ^ rank;
            }
            ChildList<Expression> typeArguments = TypeArguments;
            if (typeArguments != null)
            {
                foreach (Expression typeArgument in typeArguments)
                {
                    if (typeArgument != null)
                        hashCode ^= typeArgument.EvaluateType().GetIsSameRefHashCode();
                }
            }
            return hashCode;
        }

        /// <summary>
        /// Determine if the specified <see cref="TypeRefBase"/> refers to the same generic type, regardless of actual type arguments.
        /// </summary>
        public override bool IsSameGenericType(TypeRefBase typeRefBase)
        {
            TypeRef typeRef = (typeRefBase is AliasRef ? ((AliasRef)typeRefBase).Type : typeRefBase as TypeRef);
            return (typeRef != null && Name == typeRef.Name && NamespaceName == typeRef.NamespaceName
                && (_typeArguments != null ? _typeArguments.Count : 0) == typeRef.TypeArgumentCount && HasSameArrayRanks(typeRef));
        }

        /// <summary>
        /// True if the current type is assignable from the specified type.
        /// </summary>
        public bool IsAssignableFrom(TypeRef typeRef)
        {
            return (typeRef != null && (IsSameRef(typeRef) || typeRef.IsSubclassOf(this) || typeRef.IsImplementationOf(this)));
        }

        /// <summary>
        /// Determines if the current <see cref="TypeRef"/> is a subclass of the specified <see cref="TypeRef"/>.
        /// </summary>
        public bool IsSubclassOf(TypeRef classTypeRef)
        {
            TypeRefBase baseTypeRef = GetBaseType();
            return (baseTypeRef is TypeRef && (baseTypeRef.IsSameRef(classTypeRef) || ((TypeRef)baseTypeRef).IsSubclassOf(classTypeRef)));
        }

        /// <summary>
        /// Determines if the current <see cref="TypeRef"/> implements the specified interface <see cref="TypeRef"/>.
        /// </summary>
        public bool IsImplementationOf(TypeRef interfaceTypeRef)
        {
            if (interfaceTypeRef == null)
                return false;

            object reference = GetReferencedType();
            if (reference is ITypeDecl)
            {
                // We need to (recursively) resolve any open type arguments here, because the
                // declarations won't have access to the type parameters.
                // Only look at type declarations that can implement interfaces.
                if (reference is BaseListTypeDecl && !(reference is EnumDecl))
                {
                    BaseListTypeDecl baseListTypeDecl = (BaseListTypeDecl)reference;
                    List<Expression> baseTypes = baseListTypeDecl.GetAllBaseTypes();
                    if (baseTypes != null)
                    {
                        // Check all interfaces implemented directly by the type declaration
                        foreach (Expression baseTypeExpression in baseTypes)
                        {
                            TypeRef baseTypeRef = baseTypeExpression.EvaluateType() as TypeRef;
                            if (baseTypeRef != null && baseTypeRef.IsInterface)
                            {
                                // Resolve any open type arguments, and compare the interface to the target
                                baseTypeRef = (TypeRef)baseTypeRef.EvaluateTypeArgumentTypes(this);
                                if (baseTypeRef.IsSameRef(interfaceTypeRef))
                                    return true;
                            }
                        }
                        // If we didn't find a match yet, search any base type and/or all interfaces for implemented interfaces
                        foreach (Expression baseTypeExpression in baseTypes)
                        {
                            TypeRef baseTypeRef = baseTypeExpression.EvaluateType() as TypeRef;
                            if (baseTypeRef != null)
                            {
                                baseTypeRef = (TypeRef)baseTypeRef.EvaluateTypeArgumentTypes(this);
                                if (baseTypeRef.IsImplementationOf(interfaceTypeRef))
                                    return true;
                            }
                        }
                    }
                }
                return false;
            }
            if (reference is TypeDefinition)
            {
                TypeDefinition typeDefinition = (TypeDefinition)reference;
                bool interfaceTypeRefIsGeneric = interfaceTypeRef.IsGenericType;

                // Check all interfaces implemented directly by the type definition
                foreach (TypeReference interfaceReference in typeDefinition.Interfaces)
                {
                    // Make sure the generic status matches
                    if (interfaceReference.IsGenericInstance == interfaceTypeRefIsGeneric)
                    {
                        // Because we might need to resolve any open type arguments, we have to convert the
                        // interface to a TypeRef before we can compare it to the target interface.  We also
                        // have to do this because 'interfaceTypeRef' might refer to an InterfaceDecl even
                        // though this reference refers to a TypeDefinition.
                        TypeRefBase interfaceRef = Create(interfaceReference);
                        if (interfaceReference.HasGenericParameters || interfaceReference.IsGenericInstance)
                            interfaceRef = interfaceRef.EvaluateTypeArgumentTypes(this);
                        if (interfaceRef is TypeRef && interfaceRef.IsSameRef(interfaceTypeRef))
                            return true;
                    }
                }
                // If we didn't find a match yet, check any base type for implemented interfaces
                if (typeDefinition.BaseType != null && typeDefinition.BaseType.FullName != "System.Object")
                {
                    TypeRefBase baseTypeRef = Create(typeDefinition.BaseType);
                    baseTypeRef = baseTypeRef.EvaluateTypeArgumentTypes(this);
                    if (baseTypeRef is TypeRef && ((TypeRef)baseTypeRef).IsImplementationOf(interfaceTypeRef))
                        return true;
                }
                // If we didn't find a match yet, check all interfaces for implemented interfaces
                foreach (TypeReference interfaceReference in typeDefinition.Interfaces)
                {
                    TypeRefBase interfaceRef = Create(interfaceReference);
                    interfaceRef = interfaceRef.EvaluateTypeArgumentTypes(this);
                    if (interfaceRef is TypeRef && ((TypeRef)interfaceRef).IsImplementationOf(interfaceTypeRef))
                        return true;
                }
            }
            else if (reference is Type)
            {
                bool interfaceTypeRefIsGeneric = interfaceTypeRef.IsGenericType;

                // Search all interfaces implemented by the type or any base types
                foreach (Type @interface in ((Type)reference).GetInterfaces())
                {
                    // Make sure the generic status matches
                    if (@interface.IsGenericType == interfaceTypeRefIsGeneric)
                    {
                        // Because we might need to resolve any open type arguments, we have to convert the
                        // interface to a TypeRef before we can compare it to the target interface.  We also
                        // have to do this because 'interfaceTypeRef' might refer to an InterfaceDecl even
                        // though this reference refers to a Type.
                        TypeRef interfaceRef = Create(@interface);
                        if (@interface.IsGenericType)
                            interfaceRef = (TypeRef)interfaceRef.EvaluateTypeArgumentTypes(this);
                        if (interfaceRef.IsSameRef(interfaceTypeRef))
                            return true;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// Get all interfaces directly implemented by the type.
        /// </summary>
        public List<TypeRef> GetInterfaces(bool includeBaseInterfaces)
        {
            List<TypeRef> interfaces = new List<TypeRef>();
            object reference = GetReferencedType();
            if (reference is ITypeDecl)
            {
                // Only look at type declarations that can implement interfaces.
                if (reference is BaseListTypeDecl && !(reference is EnumDecl))
                {
                    BaseListTypeDecl baseListTypeDecl = (BaseListTypeDecl)reference;
                    List<Expression> baseTypes = baseListTypeDecl.GetAllBaseTypes();
                    if (baseTypes != null)
                    {
                        // Check all interfaces implemented directly by the type declaration
                        foreach (Expression baseTypeExpression in baseTypes)
                        {
                            TypeRef baseTypeRef = baseTypeExpression.EvaluateType() as TypeRef;
                            if (baseTypeRef != null)
                            {
                                if (baseTypeRef.IsInterface)
                                {
                                    baseTypeRef = (TypeRef)baseTypeRef.EvaluateTypeArgumentTypes(this);
                                    interfaces.Add(baseTypeRef);
                                }
                                if (includeBaseInterfaces)
                                    interfaces.AddRange(baseTypeRef.GetInterfaces(true));
                            }
                        }
                    }
                }
            }
            else if (reference is TypeDefinition)
            {
                foreach (TypeReference interfaceReference in ((TypeDefinition)reference).Interfaces)
                {
                    TypeRefBase interfaceRef = Create(interfaceReference);
                    interfaceRef = interfaceRef.EvaluateTypeArgumentTypes(this);
                    if (interfaceRef is TypeRef)
                    {
                        interfaces.Add((TypeRef)interfaceRef);
                        if (includeBaseInterfaces)
                            interfaces.AddRange(((TypeRef)interfaceRef).GetInterfaces(true));
                    }
                }
            }
            else if (reference is Type)
            {
                Type[] allInterfaces = ((Type)reference).GetInterfaces();
                if (!includeBaseInterfaces)
                {
                    // Stupid reflection doesn't provide a way to get just those interfaces implemented directly
                    // by the current type, so the best we can do is get all interfaces, then subtract those
                    // implemented by base types (even though this can produce incorrect results if the same
                    // interface is implemented at more than one level.
                    Type baseType = ((Type)reference).BaseType;
                    if (baseType != null && baseType != typeof(object))
                    {
                        Type[] baseInterfaces = baseType.GetInterfaces();
                        if (baseInterfaces.Length > 0)
                            allInterfaces = Array.FindAll(allInterfaces, delegate(Type i) { return !ArrayUtil.Contains(baseInterfaces, i); });
                    }
                }
                foreach (Type @interface in allInterfaces)
                {
                    TypeRef interfaceRef = Create(@interface);
                    interfaceRef = (TypeRef)interfaceRef.EvaluateTypeArgumentTypes(this);
                    interfaces.Add(interfaceRef);
                }
            }
            return interfaces;
        }

        /// <summary>
        /// Get all interfaces directly implemented by the type.
        /// </summary>
        public List<TypeRef> GetInterfaces()
        {
            return GetInterfaces(false);
        }

        /// <summary>
        /// Get the the underlying type if this is an enum type (otherwise returns null).
        /// </summary>
        public TypeRefBase GetUnderlyingTypeOfEnum()
        {
            if (IsEnum)
            {
                object reference = GetReferencedType();
                if (reference is EnumDecl)
                    return ((EnumDecl)reference).UnderlyingType.EvaluateType();
                if (reference is TypeDefinition)
                    return Create(TypeDefinitionUtil.GetUnderlyingTypeOfEnum((TypeDefinition)reference));
                if (reference is Type)
                    return Create(Enum.GetUnderlyingType((Type)reference));
                if (reference is EnumConstant)
                    return ((EnumConstant)reference).EnumTypeRef.GetUnderlyingTypeOfEnum();
            }
            return null;
        }

        /// <summary>
        /// Get the actual type reference, retrieving from any constant value if necessary.
        /// </summary>
        /// <returns>The <see cref="ITypeDecl"/> (<see cref="TypeDecl"/> or <see cref="TypeParameter"/>, but NOT <see cref="Alias"/>)
        /// or <see cref="TypeDefinition"/>/<see cref="Type"/> (or null if the type is unresolved).</returns>
        public override object GetReferencedType()
        {
            object reference = Reference;
            if (IsConst)
            {
                if (reference is ITypeDecl || reference is TypeDefinition || reference is Type)
                    return reference;
                if (reference is EnumConstant)
                    return ((EnumConstant)reference).EnumTypeRef.Reference;
                return reference.GetType();
            }
            return reference;
        }

        /// <summary>
        /// Get a <see cref="TypeRef"/> for the actual type, excluding any constant values.
        /// </summary>
        public override TypeRefBase GetTypeWithoutConstant()
        {
            if (IsConst)
            {
                // For an ITypeDecl or Type, return a new TypeRef without the Const flag set
                if (_reference is ITypeDecl || _reference is TypeDefinition || _reference is Type)
                {
                    TypeRef newTypeRef = (TypeRef)Clone();
                    newTypeRef.SetFormatFlag(FormatFlags.Const, false);
                    return newTypeRef;
                }
                // For an enum or primitive-type constant, return a TypeRef to the type
                if (_reference is EnumConstant)
                    return ((EnumConstant)_reference).EnumTypeRef;
                return new TypeRef(_reference.GetType(), IsFirstOnLine);
            }
            return this;
        }

        /// <summary>
        /// Get the value of any represented constant.  For enums, an <see cref="EnumConstant"/> object will be
        /// returned, which has both the Enum type and a constant value of its underlying type.
        /// </summary>
        public override object GetConstantValue()
        {
            if (IsConst)
            {
                if (_reference is ITypeDecl || _reference is TypeDefinition || _reference is Type)
                    return null;
                return _reference;
            }
            return null;
        }

        /// <summary>
        /// Get the declaring type.
        /// </summary>
        public override TypeRefBase GetDeclaringType()
        {
            object reference = GetReferencedType();
            if (reference is ITypeDecl)
            {
                CodeObject parent = ((ITypeDecl)reference).Parent;
                return (parent is TypeDecl ? ((TypeDecl)parent).CreateRef() : null);
            }
            if (reference is TypeReference)
            {
                TypeReference declaringType = ((TypeReference)reference).DeclaringType;
                return (declaringType != null ? Create(declaringType) : null);
            }
            if (reference is Type)
            {
                Type declaringType = ((Type)reference).DeclaringType;
                return (declaringType != null ? new TypeRef(declaringType) : null);
            }
            return null;
        }

        /// <summary>
        /// Get the full name of the object, including the namespace name.
        /// </summary>
        public override string GetFullName()
        {
            object reference = GetReferencedType();
            if (reference is ITypeDecl)
                return ((ITypeDecl)reference).GetFullName();
            if (reference is TypeReference)  // TypeDefinition or GenericParameter
                return ((TypeReference)reference).FullName;
            if (reference is Type)
                return ((Type)reference).Namespace + "." + ((Type)reference).Name;  // FullName might return null!
            return null;
        }

        #endregion

        #region /* PARSING */

        internal static new void AddParsePoints()
        {
            // Parse built-in types and '?' nullable types here in TypeRef, because they will
            // parse as resolved TypeRefs.  Generic types and arrays are parsed in UnresolvedRef,
            // because they may or may not parse as resolved.

            // Install parse-points for all built-in type names (without any scope restrictions) - this
            // will also parse built-in nullable types.
            foreach (KeyValuePair<string, TypeRef> keyValue in KeywordToTypeRefMap)
                Parser.AddParsePoint(keyValue.Key, ParseType);

            // Parse nullable types - use a parse-priority of 100 (Conditional uses 0)
            Parser.AddParsePoint(ParseTokenNullable, 100, ParseNullableType);
        }

        /// <summary>
        /// Parse a built-in type, or a nullable built-in type.
        /// </summary>
        private static TypeRef ParseType(Parser parser, CodeObject parent, ParseFlags flags)
        {
            return new TypeRef(parser, parent, true, flags);
        }

        /// <summary>
        /// Parse a '?' nullable type.
        /// </summary>
        private static SymbolicRef ParseNullableType(Parser parser, CodeObject parent, ParseFlags flags)
        {
            // If we get here, Conditional has already failed to parse the '?' (because it failed to find a ':'),
            // so this *should* truly be a nullable type, but still make sure it has an unused expression.
            if (parser.HasUnusedExpression)
                return new TypeRef(parser, parent, false, flags);
            return null;
        }

        /// <summary>
        /// Construct a reference to a built-in type or nullable type, or non-built-in nullable type.
        /// </summary>
        protected TypeRef(Parser parser, CodeObject parent, bool isBuiltIn, ParseFlags flags)
            : base(parser, parent)
        {
            // Handle built-in types
            if (isBuiltIn)
            {
                // Resolve built-in type name to actual Type
                TypeRef typeRef = KeywordToTypeRefMap[parser.TokenText];
                _reference = typeRef.Reference;
                parser.NextToken();  // Move past type name

                // Check for nullable types
                if (parser.Token != null)
                {
                    // For better performance, go ahead and parse any trailing '?' now if we have a value type, there's
                    // no whitespace before the '?', and our parent isn't an Is operator.  Otherwise, the '?' might be
                    // a Conditional, so we'll allow it to try parsing it instead - if it fails, we'll end up back here
                    // later in ParseNullableType, which will take care of it.
                    if (parser.TokenText == ParseTokenNullable && typeRef.IsValueType
                        && parser.Token.LeadingWhitespace.Length == 0 && !(_parent is Is))
                    {
                        parser.NextToken();  // Move past '?'
                        typeRef = (TypeRef)typeRef.Clone();
                        typeRef.SetLineCol(this);
                        CreateTypeArguments().Add(typeRef);
                        _reference = Nullable1Ref.Reference;
                    }
                }
            }
            else  // Handle nullable types
            {
                _reference = Nullable1Ref.Reference;
                parser.NextToken();  // Move past '?'
                Expression expression = parser.RemoveLastUnusedExpression();
                Expression leftExpression = expression;
                while (leftExpression is BinaryOperator)
                    leftExpression = ((BinaryOperator)leftExpression).Left;
                if (leftExpression != null)
                    SetLineCol(leftExpression);
                IsFirstOnLine = expression.IsFirstOnLine;
                expression.IsFirstOnLine = false;
                CreateTypeArguments().Add(expression);
            }

            // Handle array types
            if (parser.TokenText == ParseTokenArrayStart && !flags.HasFlag(ParseFlags.NoArrays))
            {
                Token next = parser.PeekNextToken();
                if (next != null && (next.Text == ParseTokenArrayEnd || next.Text == ParseTokenSeparator))
                    ParseArrayRanks(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)
        {
            // Do NOT unresolve if it's a built-in type
            if (flags.HasFlag(ResolveFlags.Unresolve) && IsBuiltInType)
                return this;

            return base.Resolve(resolveCategory, flags);
        }

        /// <summary>
        /// Resolve child code objects that match the specified name.
        /// </summary>
        public override void ResolveRef(string name, Resolver resolver)
        {
            if (HasArrayRanks)
                ResolveRef(ArrayRef, name, resolver);
            else
                ResolveRef(this, name, resolver);
        }

        /// <summary>
        /// Resolve child code objects in the specified <see cref="TypeRef"/> that match the specified name.
        /// </summary>
        public static void ResolveRef(TypeRef typeRef, string name, Resolver resolver)
        {
            object reference = typeRef.GetReferencedType();
            if (reference is ITypeDecl)
                ((ITypeDecl)reference).ResolveRef(name, resolver);
            else if (reference is TypeReference)  // TypeDefinition or GenericParameter
                ResolveRef((TypeReference)reference, name, resolver);
            else if (reference is Type)
                ResolveRef((Type)reference, name, resolver);
        }

        /// <summary>
        /// Resolve indexers.
        /// </summary>
        public override void ResolveIndexerRef(Resolver resolver)
        {
            object reference = GetReferencedType();
            if (reference != null)
            {
                if (reference is ITypeDecl)
                    ((ITypeDecl)reference).ResolveIndexerRef(resolver);
                else if (reference is TypeReference)  // TypeDefinition or GenericParameter
                    ResolveIndexerRef((TypeReference)reference, resolver);
                else if (reference is Type)
                    ResolveIndexerRef((Type)reference, resolver);
            }
        }

        /// <summary>
        /// Resolve child code objects in the specified <see cref="TypeReference"/> that match the specified name.
        /// </summary>
        public static void ResolveRef(TypeReference typeReference, string name, Resolver resolver)
        {
            // The search name must include the type parameter count to find generic nested types, but NOT
            // to find generic methods (which is good, since they can have implicit type parameters).  So,
            // we must add the type parameter count only if we're looking for a type.
            string searchName = name;
            if (resolver.IsGenericTypeOrConstructor)
                searchName += "`" + resolver.TypeArgumentCount;

            // Search for the member in the type (don't search base types - we need to search them
            // one by one to avoid finding multiple results due to 'new' or overloaded members).
            TypeDefinition typeDefinition = null;
            try { typeDefinition = typeReference.Resolve(); }
            catch { }
            if (typeDefinition != null)
            {
                resolver.AddMatch(TypeDefinitionUtil.GetMembers(typeDefinition, searchName));

                if (!resolver.HasCompleteMatch)
                {
                    // Recursively search any base type(s) if we haven't found anything yet
                    if (typeDefinition.BaseType != null)
                        ResolveRef(typeDefinition.BaseType, name, resolver);
                    else if (typeDefinition.IsInterface)
                    {
                        // If we're searching an interface, we have to manually search any base interfaces.
                        ResolveRefInBaseInterfaces(typeDefinition, searchName, resolver);

                        // If we still didn't find anything, also search the implicit 'object' base
                        if (!resolver.HasCompleteMatch)
                            ResolveRef(ObjectRef, name, resolver);
                    }
                }
            }
        }

        /// <summary>
        /// Search for members with the specified name in all base interfaces of the specified <see cref="TypeReference"/>, accumulating the results.
        /// </summary>
        public static void ResolveRefInBaseInterfaces(TypeReference typeReference, string searchName, Resolver resolver)
        {
            // Find all matching interface members in the immediate base interfaces
            TypeDefinition typeDefinition = null;
            try { typeDefinition = typeReference.Resolve(); }
            catch { }
            if (typeDefinition != null)
            {
                Collection<TypeReference> interfaces = typeDefinition.Interfaces;
                foreach (TypeReference interfaceTypeReference in interfaces)
                {
                    TypeDefinition interfaceTypeDefinition = null;
                    try { interfaceTypeDefinition = interfaceTypeReference.Resolve(); }
                    catch { }
                    if (interfaceTypeDefinition != null)
                    {
                        resolver.AddMatch(TypeDefinitionUtil.GetMembers(interfaceTypeDefinition, searchName));

                        // Stop if we found a match - otherwise, for example, ICollection<T> implements both IEnumerable<T> AND IEnumerable,
                        // even though IEnumerable<T> also implements IEnumerable and these two interfaces share method signatures.  So we
                        // either have to stop after a match, or we have to filter out 'base' interfaces as we do in the version of this
                        // method that handles reflection Types even though the Interfaces collection used here is only one 'level' deep.
                        if (resolver.HasCompleteMatch)
                            break;
                    }
                }

                // If we didn't find anything, look in any base interfaces
                if (!resolver.HasCompleteMatch)
                {
                    foreach (TypeReference interfaceTypeReference in interfaces)
                        ResolveRefInBaseInterfaces(interfaceTypeReference, searchName, resolver);
                }
            }
        }

        /// <summary>
        /// Resolve indexers in the specified <see cref="TypeReference"/>.
        /// </summary>
        public static void ResolveIndexerRef(TypeReference typeReference, Resolver resolver)
        {
            // Search for all indexed properties in the type (don't search base types - we need to search
            // them one by one to avoid finding multiple results due to 'new' or overloaded members).
            AddIndexerMembers(typeReference, resolver);

            if (!resolver.HasCompleteMatch)
            {
                // Recursively search any base type(s) if we haven't found anything yet
                TypeDefinition typeDefinition = null;
                try { typeDefinition = typeReference.Resolve(); }
                catch { }
                if (typeDefinition != null)
                {
                    if (typeDefinition.BaseType != null)
                        ResolveIndexerRef(typeDefinition.BaseType, resolver);
                    else if (typeDefinition.IsInterface)
                    {
                        // If we're searching an interface, we have to manually search any base interfaces
                        foreach (TypeReference interfaceReference in typeDefinition.Interfaces)
                            AddIndexerMembers(interfaceReference, resolver);
                    }
                }
            }
        }

        private static void AddIndexerMembers(TypeReference typeReference, Resolver resolver)
        {
            TypeDefinition typeDefinition = null;
            try { typeDefinition = typeReference.Resolve(); }
            catch { }
            if (typeDefinition != null)
            {
                // We don't want to match any explicit interface implementations, so filter those out
                IEnumerable<PropertyDefinition> indexerDefinitions = Enumerable.Where(typeDefinition.Properties, delegate(PropertyDefinition property) { return property.HasParameters; });
                foreach (PropertyDefinition indexerDefinition in indexerDefinitions)
                {
                    if (!StringUtil.Contains(indexerDefinition.Name, '.'))
                        resolver.AddMatch(indexerDefinition);
                }
            }
        }

        /// <summary>
        /// Resolve child code objects in the specified <see cref="Type"/> that match the specified name.
        /// </summary>
        public static void ResolveRef(Type type, string name, Resolver resolver)
        {
            try
            {
                // Type.GetMember() requires the search name to include the type parameter count to find generic
                // nested types, but NOT to find generic methods (which is good, since they can have implicit
                // type parameters).  So, we must add the type parameter count only if we're looking for a type.
                // Since methods can be in the Expression category in addition to Method, we'll add it for the
                // type and constructor categories.  If it turns out we might match a type in an Expression,
                // we'll have to search both ways and combine the results.
                string searchName = name;
                if (resolver.IsGenericTypeOrConstructor)
                    searchName += "`" + resolver.TypeArgumentCount;

                // Make sure to use the generic type definition, or the returned members might have type
                // parameters that map to some other parent type that instantiated a generic type.
                Type lookupType = (type.IsGenericType && !type.IsGenericTypeDefinition ? type.GetGenericTypeDefinition() : type);

                // Search for the member in the type (don't search base types - we need to search them
                // one by one to avoid finding multiple results due to 'new' or overloaded members).
                MemberInfo[] memberInfos = lookupType.GetMember(searchName, BindingFlags.DeclaredOnly
                    | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
                resolver.AddMatch(memberInfos);

                if (!resolver.HasCompleteMatch)
                {
                    // Recursively search any base type(s) if we haven't found anything yet
                    if (type.BaseType != null)
                        ResolveRef(type.BaseType, name, resolver);
                    else if (type.IsInterface)
                    {
                        // If we're searching an interface, we have to manually search any base interfaces.
                        ResolveRefInBaseInterfaces(type, searchName, resolver);

                        // If we still didn't find anything, also search the implicit 'object' base
                        if (!resolver.HasCompleteMatch)
                            ResolveRef(typeof(object), name, resolver);
                    }
                }
            }
            catch
            {
                // Ignore any exceptions - can be caused by missing dependent assemblies
            }
        }

        /// <summary>
        /// Search for members with the specified name in all base interfaces of the specified <see cref="Type"/>, accumulating the results.
        /// </summary>
        public static void ResolveRefInBaseInterfaces(Type type, string searchName, Resolver resolver)
        {
            try
            {
                // There's no way to search up the hierarchy one level at a time - ALL base interfaces are
                // returned by GetInterfaces(), whether they were specified in the immediate base list or not!!
                // So, we have to manually filter out the "deeper" ones.
                List<Type> interfaces = new List<Type>(type.GetInterfaces());
                if (interfaces.Count > 1)
                {
                    // Scan the interfaces in reverse, removing any that are a base interface of another one in
                    // order to determine only the immediate base interfaces.
                    for (int i = interfaces.Count - 1; i >= 0; --i)
                    {
                        foreach (Type @interface in interfaces)
                        {
                            if (@interface != interfaces[i] && @interface.GetInterface(interfaces[i].Name) != null)
                            {
                                interfaces.RemoveAt(i);
                                break;
                            }
                        }
                    }
                }

                // Find all matching interface members in the immediate base interfaces
                foreach (Type interfaceType in interfaces)
                    resolver.AddMatch(interfaceType.GetMember(searchName));

                // If we didn't find anything, look in any base interfaces
                if (!resolver.HasCompleteMatch)
                {
                    foreach (Type interfaceType in interfaces)
                        ResolveRefInBaseInterfaces(interfaceType, searchName, resolver);
                }
            }
            catch
            {
                // Ignore any exceptions - can be caused by missing dependent assemblies
            }
        }

        /// <summary>
        /// Resolve indexers in the specified <see cref="Type"/>.
        /// </summary>
        public static void ResolveIndexerRef(Type type, Resolver resolver)
        {
            try
            {
                // Make sure to use the generic type definition, or the returned members might have type
                // parameters that map to some other parent type that instantiated a generic type.
                Type lookupType = (type.IsGenericType && !type.IsGenericTypeDefinition ? type.GetGenericTypeDefinition() : type);

                // Search for all indexed properties in the type (don't search base types - we need to search
                // them one by one to avoid finding multiple results due to 'new' or overloaded members).
                MemberInfo[] memberInfos = lookupType.GetMembers(BindingFlags.DeclaredOnly
                    | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                AddIndexerMembers(memberInfos, resolver);

                if (!resolver.HasCompleteMatch)
                {
                    // Recursively search any base type(s) if we haven't found anything yet
                    if (type.BaseType != null)
                        ResolveIndexerRef(type.BaseType, resolver);
                    else if (type.IsInterface)
                    {
                        // If we're searching an interface, we have to manually search any base interfaces
                        foreach (Type interfaceType in type.GetInterfaces())
                            AddIndexerMembers(interfaceType.GetMembers(), resolver);
                    }
                }
            }
            catch
            {
                // Ignore any exceptions - can be caused by missing dependent assemblies
            }
        }

        private static void AddIndexerMembers(MemberInfo[] memberInfos, Resolver resolver)
        {
            // Although indexers (which always display their name as 'this') usually have an internal name of 'Item',
            // the IndexerName attribute can be used to override the name.  For example, StringBuilder has an indexer
            // named 'Chars', XmlAttributeCollection has 'ItemOf', etc.  So, we have to scan for all PropertyInfos
            // that represent indexers.  Also, we don't want to match any explicit interface implementations, so filter
            // those out.
            foreach (MemberInfo memberInfo in memberInfos)
            {
                if (memberInfo is PropertyInfo)
                {
                    PropertyInfo propertyInfo = (PropertyInfo)memberInfo;
                    if (PropertyInfoUtil.IsIndexed(propertyInfo) && !StringUtil.Contains(propertyInfo.Name, '.'))
                        resolver.AddMatch(memberInfo);
                }
            }
        }

        /// <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)
        {
            return this;
        }

        /// <summary>
        /// Find a type argument for the specified type parameter.
        /// </summary>
        public override TypeRefBase FindTypeArgument(TypeParameterRef typeParameterRef, CodeObject originatingChild)
        {
            // Search any type arguments
            TypeRefBase typeRefBase = null;
            if (HasTypeArguments)
            {
                typeRefBase = FindTypeArgumentInTypeArguments(typeParameterRef);

                // If we didn't find a match, also recursively search any nested type arguments
                if (typeRefBase == null)
                    typeRefBase = FindNestedTypeArgument(typeParameterRef);
            }

            // If we didn't find a match in the type arguments of the referenced type, also search any base
            // types, evaluating any type arguments at the current level.
            if (typeRefBase == null)
            {
                typeRefBase = FindTypeArgumentInBase(typeParameterRef);
                if (typeRefBase != null)
                    typeRefBase = typeRefBase.EvaluateTypeArgumentTypes(this, originatingChild);
            }
            return typeRefBase;
        }

        /// <summary>
        /// Find a type argument in a base class for the specified type parameter.
        /// </summary>
        public TypeRefBase FindTypeArgumentInBase(TypeParameterRef typeParameterRef)
        {
            object reference = GetReferencedType();
            if (reference is TypeDecl)
                return ((TypeDecl)reference).FindTypeArgumentInBase(typeParameterRef);
            if (reference is TypeReference && typeParameterRef.Reference is GenericParameter)
                return Create(TypeDefinitionUtil.FindTypeArgumentInBase((TypeReference)reference, typeParameterRef.Reference as GenericParameter));
            if (reference is Type && typeParameterRef.Reference is Type)
                return Create(TypeUtil.FindTypeArgumentInBase((Type)reference, typeParameterRef.Reference as Type));
            return null;
        }

        private static bool[,] _typeConversionMap;

        /// <summary>
        /// Determine if the TypeRef 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)
        {
            // Implicit identity conversion
            if (ImplicitIdentityConversionExists(toTypeRefBase))
                return true;

            // Implicit reference conversions
            if (ImplicitReferenceConversionExists(toTypeRefBase, standardConversionsOnly))
                return true;

            TypeRef toTypeRef = toTypeRefBase as TypeRef;
            if (toTypeRef == null)
                return false;

            // If either or both types are arrays, there's no conversion at this point (the legal ones are handled above)
            if (!IsArray && !toTypeRef.IsArray)
            {
                // Implicit numeric conversions
                if (IsPrimitive && (toTypeRef.IsPrimitive || toTypeRef.IsSameRef(DecimalRef)))
                {
                    #region /* STATIC MAPPING TABLE CREATION */

                    if (_typeConversionMap == null)
                    {
                        // The TypeCode enum looks like this:
                        // 0-Empty, 1-Object, 2-DBNull, 3-Boolean, 4-Char, 5-SByte, 6-Byte, 7-Int16, 8-UInt16, 9-Int32,
                        // 10-UInt32, 11-Int64, 12-UInt64, 13-Single, 14-Double, 15-Decimal, 16-DateTime, 17-String
                        // We will 'cheat' a bit here and use knowledge of this ordering to create a mapping table
                        // for a subset of these for common type conversions.
                        _typeConversionMap = new[,]
                            {  // char   sbyte  byte   short  ushort int    uint   long   ulong  float double decimal  // FROM:
                                { true,  false, false, false, true,  true,  true,  true,  true,  true, true, true  },  // char
                                { false, true,  false, true,  false, true,  false, true,  false, true, true, true  },  // sbyte
                                { false, false, true,  true,  true,  true,  true,  true,  true,  true, true, true  },  // byte
                                { false, false, false, true,  false, true,  false, true,  false, true, true, true  },  // short
                                { false, false, false, false, true,  true,  true,  true,  true,  true, true, true  },  // ushort
                                { false, false, false, false, false, true,  false, true,  false, true, true, true  },  // int
                                { false, false, false, false, false, false, true,  true,  true,  true, true, true  },  // uint
                                { false, false, false, false, false, false, false, true,  false, true, true, true  },  // long
                                { false, false, false, false, false, false, false, false, true,  true, true, true  },  // ulong
                                { false, false, false, false, false, false, false, false, false, true, true, false }   // float
                                // Double & Decimal rows are omitted, because all entries (except identity) would be 'false'
                            };
                    }

                    #endregion

                    // Check if the implicit conversion is possible
                    TypeCode fromTypeCode = GetTypeCode();
                    TypeCode toTypeCode = toTypeRef.GetTypeCode();
                    if (fromTypeCode >= TypeCode.Char && fromTypeCode <= TypeCode.Single && toTypeCode >= TypeCode.Char && toTypeCode <= TypeCode.Decimal)
                        return _typeConversionMap[fromTypeCode - TypeCode.Char, toTypeCode - TypeCode.Char];
                }

                // Boxing conversions
                if (BoxingConversionExists(toTypeRef))
                    return true;

                // Implicit nullable conversions
                // Convert between S? and T? or S and T?, where an implicit conversion from S to T exists.
                if (toTypeRef.IsNullableType && IsValueType)
                {
                    TypeRefBase destinationRef = toTypeRef.TypeArguments[0].EvaluateType();
                    TypeRefBase sourceRef = this;
                    if (IsNullableType)
                        sourceRef = TypeArguments[0].EvaluateType();
                    return (sourceRef != null && destinationRef != null && sourceRef.IsImplicitlyConvertibleTo(destinationRef));
                }

                // User-defined implicit conversions
                if (!standardConversionsOnly)
                    return UserDefinedImplicitConversionExists(toTypeRef);

                // For implicit conversions involving type parameters, see TypeParameterRef.IsImplicitlyConvertibleTo()
                // For anonymous function conversions, see AnonymousMethodRef.IsImplicitlyConvertibleTo()
                // For method group conversions, see MethodRef.IsImplicitlyConvertibleTo()
            }

            return false;
        }

        /// <summary>
        /// Determine if an implicit identity conversion exists to the specified type.
        /// </summary>
        public override bool ImplicitIdentityConversionExists(TypeRefBase toTypeRefBase)
        {
            // No conversion if we're unresolved (can happen if we're actually a VarTypeRef)
            if (Reference == null)
                return false;

            // Implicit identity conversion
            if (IsSameRef(toTypeRefBase))
                return true;

            return false;
        }

        /// <summary>
        /// Determine if an implicit reference conversion exists to the specified type.
        /// </summary>
        public override bool ImplicitReferenceConversionExists(TypeRefBase toTypeRefBase, bool standardConversionsOnly)
        {
            object reference = Reference;

            // No conversion if we're unresolved (can happen if we're actually a VarTypeRef)
            if (reference == null)
                return false;

            TypeRef toTypeRef = toTypeRefBase as TypeRef;
            if (toTypeRef == null)
                return false;

            // Special handling when the destination is a type parameter - allow conversion if any of the constraints are compatible
            if (toTypeRef is TypeParameterRef)
                return toTypeRef.IsImplicitlyConvertibleFrom(this);

            // Special handling for similar generic types
            if (IsGenericType && toTypeRef.IsGenericType && reference == toTypeRef.Reference && !IsArray && !toTypeRef.IsArray)
            {
                // Allow conversion if the destination is the same generic type with type parameters whose constraints
                // are compatible with those of the source type.
                // Allow either the destination OR the source type parameters to be TypeParameterRefs - as long as they
                // are implicitly convertible, it should be OK.
                ChildList<Expression> typeArguments = TypeArguments;
                ChildList<Expression> toTypeArguments = toTypeRef.TypeArguments;
                int argumentCount = typeArguments.Count;
                if (argumentCount == toTypeArguments.Count)
                {
                    bool allow = true;
                    for (int i = 0; i < argumentCount; ++i)
                    {
                        TypeRef destinationRef = toTypeArguments[i] as TypeRef;
                        TypeRef sourceRef = typeArguments[i] as TypeRef;
                        if (destinationRef == null || sourceRef == null || !(destinationRef is TypeParameterRef || sourceRef is TypeParameterRef)
                            || !destinationRef.IsImplicitlyConvertibleFrom(sourceRef))
                        {
                            allow = false;
                            break;
                        }
                    }
                    if (allow)
                        return true;
                }
            }

            if (IsValueType)
            {
                if (IsConst)
                {
                    switch (Type.GetTypeCode(reference.GetType()))
                    {
                        case TypeCode.SByte:
                            // Implicit enumeration conversions (between any integer literal 0 and any enum type, or nullable enum type)
                            if ((sbyte)reference == 0 && !standardConversionsOnly && IsEnumOrNullableEnum(toTypeRef))
                                return true;
                            break;
                        case TypeCode.Byte:
                            // Implicit enumeration conversions (between any integer literal 0 and any enum type, or nullable enum type)
                            if ((byte)reference == 0 && !standardConversionsOnly && IsEnumOrNullableEnum(toTypeRef))
                                return true;
                            break;
                        case TypeCode.Int16:
                            // Implicit enumeration conversions (between any integer literal 0 and any enum type, or nullable enum type)
                            if ((short)reference == 0 && !standardConversionsOnly && IsEnumOrNullableEnum(toTypeRef))
                                return true;
                            break;
                        case TypeCode.UInt16:
                            // Implicit enumeration conversions (between any integer literal 0 and any enum type, or nullable enum type)
                            if ((ushort)reference == 0 && !standardConversionsOnly && IsEnumOrNullableEnum(toTypeRef))
                                return true;
                            break;
                        case TypeCode.Int32:
                        {
                            int value = (int)reference;

                            // Implicit enumeration conversions (between any integer literal 0 and any enum type, or nullable enum type)
                            if (value == 0 && !standardConversionsOnly && IsEnumOrNullableEnum(toTypeRef))
                                return true;

                            // Implicit constant expression conversions
                            //    A constant-expression of type int can be converted to type sbyte, byte, short, ushort, uint, or ulong,
                            //    provided the value of the constant-expression is within the range of the destination type.
                            if (toTypeRef.IsPrimitive)
                            {
                                switch (toTypeRef.GetTypeCode())
                                {
                                    case TypeCode.SByte:  return (value >= sbyte.MinValue && value <= sbyte.MaxValue);
                                    case TypeCode.Byte:   return (value >= 0 && value <= byte.MaxValue);
                                    case TypeCode.Int16:  return (value >= short.MinValue && value <= short.MaxValue);
                                    case TypeCode.UInt16: return (value >= 0 && value <= ushort.MaxValue);
                                    case TypeCode.UInt32: return (value >= 0);
                                    case TypeCode.UInt64: return (value >= 0);
                                }
                            }
                            break;
                        }
                        case TypeCode.UInt32:
                            // Implicit enumeration conversions (between any integer literal 0 and any enum type, or nullable enum type)
                            if ((uint)reference == 0 && !standardConversionsOnly && IsEnumOrNullableEnum(toTypeRef))
                                return true;
                            break;
                        case TypeCode.Int64:
                        {
                            long value = (long)reference;

                            // Implicit enumeration conversions (between any integer literal 0 and any enum type, or nullable enum type)
                            if (value == 0 && !standardConversionsOnly && IsEnumOrNullableEnum(toTypeRef))
                                return true;

                            // Implicit constant expression conversions
                            //    A constant-expression of type long can be converted to type ulong, provided the value isn't negative.
                            if (toTypeRef.IsSameRef(ULongRef))
                                return (value >= 0);

                            break;
                        }
                        case TypeCode.UInt64:
                            // Implicit enumeration conversions (between any integer literal 0 and any enum type, or nullable enum type)
                            if ((ulong)reference == 0 && !standardConversionsOnly && IsEnumOrNullableEnum(toTypeRef))
                                return true;
                            break;
                        case TypeCode.Double:
                            // Implicit enumeration conversions (between any integer literal 0 and any enum type, or nullable enum type)
                            if ((double)reference == 0 && !standardConversionsOnly && IsEnumOrNullableEnum(toTypeRef))
                                return true;
                            break;
                    }
                }
            }
            else
            {
                // Implicit reference conversions

                // - From any reference-type (including arrays) to object
                if (toTypeRef.IsSameRef(ObjectRef))
                    return true;

                List<int> arrayRanks = ArrayRanks;
                int arrayRanksCount = (arrayRanks != null ? arrayRanks.Count : 0);
                if (arrayRanksCount == 0)
                {
                    // - From the null literal to any reference type or nullable type
                    if (IsConst && IsSameRef(ObjectRef))
                        return (!toTypeRef.IsValueType || (toTypeRef.IsNullableType && !standardConversionsOnly));

                    if (!toTypeRef.IsArray)
                    {
                        // - From any class-type S to any class-type T, provided S is derived from T
                        if (IsClass && toTypeRef.IsClass && IsSubclassOf(toTypeRef))
                            return true;

                        bool isDelegateType;

                        // - From any class-type S to any interface-type T, provided S implements T
                        // - From any interface-type S to any interface-type T, provided S is derived from T
                        if (toTypeRef.IsInterface)
                        {
                            if (IsImplementationOf(toTypeRef))
                                return true;
                            isDelegateType = IsDelegateType;
                        }
                        else if (toTypeRef.IsDelegateType)
                        {
                            // Implicit conversions exist between any two delegate types with identical parameters and return types
                            isDelegateType = IsDelegateType;
                            if (isDelegateType)
                            {
                                TypeRefBase returnTypeRef = GetDelegateReturnType();
                                if (returnTypeRef != null && returnTypeRef.IsSameRef(toTypeRef.GetDelegateReturnType()) && HasSameDelegateParameters(toTypeRef))
                                    return true;
                            }
                        }
                        else
                            isDelegateType = IsDelegateType;

                        // - From any delegate-type to System.MulticastDelegate or System.Delegate, or the interfaces they implement
                        if (isDelegateType && (toTypeRef.IsSameRef(MulticastDelegateRef) || toTypeRef.IsSameRef(DelegateRef)
                            || toTypeRef.IsSameRef(ICloneableRef) || toTypeRef.IsSameRef(ISerializableRef)))
                            return true;
                    }
                }
                else
                {
                    // From an array-type S with an element type SE to an array-type T with an element type TE, provided all of the following are true:
                    //    - S and T differ only in element type. In other words, S and T have the same number of dimensions
                    //    - Both SE and TE are reference-types
                    //    - An implicit reference conversion exists from SE to TE
                    if (toTypeRef.IsArray)
                    {
                        if (arrayRanksCount == 1 && toTypeRef.ArrayRanks.Count == 1 && arrayRanks[0] == toTypeRef.ArrayRanks[0])
                        {
                            TypeRef thisElementTypeRef = (TypeRef)GetElementType();
                            TypeRef elementTypeRef = (TypeRef)toTypeRef.GetElementType();
                            if (!thisElementTypeRef.IsValueType && !elementTypeRef.IsValueType && thisElementTypeRef.IsImplicitlyConvertibleTo(elementTypeRef))
                                return true;
                        }
                    }
                    else
                    {
                        // From any array-type to System.Array -OR- any of its base interfaces
                        if (toTypeRef.IsSameRef(ArrayRef) || toTypeRef.IsSameRef(ICloneableRef) || toTypeRef.IsSameRef(IListRef)
                            || toTypeRef.IsSameRef(ICollectionRef) || toTypeRef.IsSameRef(IEnumerableRef))
                            return true;

                        // From a single-dimensional array type S[] (or S[...][], etc) to System.Collections.Generic.IList<T> and
                        // its base interfaces, provided that there is an implicit identity or reference conversion from S to T.
                        if (arrayRanksCount >= 1 && arrayRanks[0] == 1 && toTypeRef.IsInterface)
                        {
                            if (toTypeRef.IsSameRef(IEnumerableRef))
                                return true;
                            if (toTypeRef.IsGenericType)
                            {
                                if (toTypeRef.IsSameGenericType(IList1Ref) || toTypeRef.IsSameGenericType(ICollection1Ref) || toTypeRef.IsSameGenericType(IEnumerable1Ref))
                                {
                                    TypeRefBase elementTypeRef = GetElementType();
                                    TypeRefBase typeRefBase = (toTypeRef.TypeArgumentCount > 0 ? toTypeRef.TypeArguments[0].EvaluateType() : null);
                                    if (elementTypeRef.ImplicitIdentityConversionExists(typeRefBase) || elementTypeRef.ImplicitReferenceConversionExists(typeRefBase, standardConversionsOnly))
                                        return true;
                                }
                            }
                        }
                    }
                }
            }

            return false;
        }

        protected bool HasSameDelegateParameters(TypeRef toTypeRef)
        {
            ICollection parameters = GetDelegateParameters();
            ICollection toParameters = toTypeRef.GetDelegateParameters();
            int parameterCount = (parameters != null ? parameters.Count : 0);
            if (parameterCount == (toParameters != null ? toParameters.Count : 0))
            {
                for (int i = 0; i < parameterCount; ++i)
                {
                    bool isRef, isOut, toIsRef, toIsOut;
                    TypeRefBase parameterRef = ParameterRef.GetParameterType(parameters, i, out isRef, out isOut, this);
                    TypeRefBase toParameterRef = ParameterRef.GetParameterType(toParameters, i, out toIsRef, out toIsOut, toTypeRef);
                    if (parameterRef == null || !parameterRef.IsSameRef(toParameterRef) || isRef != toIsRef || isOut != toIsOut)
                        return false;
                }
                return true;
            }
            return false;
        }

        protected bool IsEnumOrNullableEnum(TypeRef typeRef)
        {
            if (typeRef.IsEnum)
                return true;
            if (typeRef.IsNullableType)
            {
                TypeRef typeArgumentRef = typeRef.TypeArguments[0].EvaluateType() as TypeRef;
                if (typeArgumentRef != null && typeArgumentRef.IsEnum)
                    return true;
            }
            return false;
        }

        /// <summary>
        /// Determine if a boxing conversion exists to the specified type.
        /// </summary>
        protected bool BoxingConversionExists(TypeRef typeRef)
        {
            if (IsValueType)
            {
                if (!IsNullableType)
                {
                    // A boxing conversion exists from any non-nullable-value-type to object, System.ValueType,
                    // and to any interface-type implemented by the non-nullable-value-type.
                    if (typeRef.IsSameRef(ObjectRef) || typeRef.IsSameRef(ValueTypeRef) || (typeRef.IsInterface && IsImplementationOf(typeRef)))
                        return true;

                    // An enum-type can be converted to the type System.Enum.
                    if (IsEnum && typeRef.IsSameRef(EnumRef))
                        return true;
                }
                else
                {
                    // A boxing conversion exists from a nullable-type to a reference type, if and only if a boxing conversion
                    // exists from the underlying non-nullable-value-type to the reference type.
                    if (!typeRef.IsValueType)
                    {
                        TypeRef argumentTypeRef = TypeArguments[0].EvaluateType() as TypeRef;
                        if (argumentTypeRef != null)
                            return argumentTypeRef.BoxingConversionExists(typeRef);
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// Find all user-defined implicit conversion operators to the specified type.
        /// </summary>
        protected NamedCodeObjectGroup FindUserDefinedImplicitConversions(TypeRef targetRef, bool referenceConversionsOnly)
        {
            // Get the types from which user-defined conversion operators will be considered.
            // If the source (S) or target (T) are nullable, get the underlying type instead.
            TypeRef sourceRef = this;
            if (IsNullableType)
                sourceRef = TypeArguments[0].EvaluateType() as TypeRef;
            if (targetRef.IsNullableType)
                targetRef = targetRef.TypeArguments[0].EvaluateType() as TypeRef;

            // Abort now if either type is null or an interface, or if we're only allowing reference conversions and the source isn't a class,
            // or if at least one of the source or target isn't a user-defined class or struct.
            if (sourceRef == null || targetRef == null || sourceRef.IsInterface || targetRef.IsInterface
                || (referenceConversionsOnly && !sourceRef.IsUserClass)
                || !(sourceRef.IsUserClass || sourceRef.IsUserStruct || targetRef.IsUserClass || targetRef.IsUserStruct))
                return null;

            // Get all user-defined conversion operators from the types.
            // Include any base-classes of S, but NOT those of T.
            const string name = "op_Implicit";
            NamedCodeObjectGroup conversions = new NamedCodeObjectGroup();
            sourceRef.GetMethods(name, true, conversions);
            targetRef.GetMethods(name, false, conversions);

            // Determine the applicable operators: those that convert from a type encompassing S to
            // a type encompassed by T (allows for standard implicit conversions before and/or after
            // the user-defined implicit conversion).
            for (int i = conversions.Count - 1; i >= 0; --i)
            {
                object obj = conversions[i];
                TypeRefBase fromType, toType;
                GetConversionFromAndToTypes(obj, out fromType, out toType);
                if (fromType == null || toType == null)
                    conversions.RemoveAt(i);
                else
                {
                    fromType = fromType.EvaluateTypeArgumentTypes(targetRef);
                    toType = toType.EvaluateTypeArgumentTypes(targetRef);
                    if (!IsEncompassedBy(sourceRef, fromType) || !IsEncompassedBy(toType, targetRef))
                        conversions.RemoveAt(i);
                }
            }
            if (conversions.Count <= 1)
                return conversions;

            // More than one applicable conversion exists - try to narrow the results to a single best-match.
            // Remove any conversions which don't have the most-specific source and target types.
            // Go forward through the list, checking all remaining conversions against the current one
            // (conversions will often be defined in order of increasing type size, so this is more efficient).
        restart:
            for (int i = 0; i < conversions.Count; ++i)
            {
                object obj1 = conversions[i];
                TypeRefBase fromType1, toType1;
                GetConversionFromAndToTypes(obj1, out fromType1, out toType1);

                // Scan all remaining conversions in reverse order, so we can remove them without consequences.
                for (int j = conversions.Count - 1; j > i; --j)
                {
                    object obj2 = conversions[j];
                    TypeRefBase fromType2, toType2;
                    GetConversionFromAndToTypes(obj2, out fromType2, out toType2);

                    if (!fromType1.IsSameRef(fromType2))
                    {
                        // If the source type of the first object is better than the 2nd, remove the 2nd
                        if (fromType1.IsSameRef(sourceRef) || (IsEncompassedBy(fromType1, fromType2) && !fromType2.IsSameRef(sourceRef)))
                        {
                            conversions.RemoveAt(j);
                            continue;
                        }
                        // Also check if the 2nd object is better than the first, and remove and restart the process if so
                        // (won't happen often if conversions are ordered properly).
                        if (fromType2.IsSameRef(sourceRef) || IsEncompassedBy(fromType2, fromType1))
                        {
                            conversions.RemoveAt(i);
                            goto restart;
                        }
                    }
                    if (!toType1.IsSameRef(toType2))
                    {
                        // If the destination type of the first object is better than the 2nd, remove the 2nd
                        if (toType1.IsSameRef(targetRef) || (IsEncompassedBy(toType1, toType2) && !toType2.IsSameRef(targetRef)))
                        {
                            conversions.RemoveAt(j);
                            continue;
                        }
                        // Also check if the 2nd object is better than the first, and remove and restart the process if so
                        // (won't happen often if conversions are ordered properly).
                        if (toType2.IsSameRef(targetRef) || IsEncompassedBy(toType2, toType1))
                        {
                            conversions.RemoveAt(i);
                            goto restart;
                        }
                    }
                }
            }

            return conversions;
        }

        /// <summary>
        /// Find all user-defined implicit conversion operators to the specified type.
        /// </summary>
        protected NamedCodeObjectGroup FindUserDefinedImplicitConversions(TypeRef targetRef)
        {
            return FindUserDefinedImplicitConversions(targetRef, false);
        }

        /// <summary>
        /// Determine if a user-defined implicit conversion exists to the specified type.
        /// </summary>
        public bool UserDefinedImplicitConversionExists(TypeRef targetRef, bool referenceConversionsOnly)
        {
            NamedCodeObjectGroup conversions = FindUserDefinedImplicitConversions(targetRef, referenceConversionsOnly);
            return (conversions != null && conversions.Count > 0);
        }

        /// <summary>
        /// Determine if a user-defined implicit conversion exists to the specified type.
        /// </summary>
        public bool UserDefinedImplicitConversionExists(TypeRef targetRef)
        {
            NamedCodeObjectGroup conversions = FindUserDefinedImplicitConversions(targetRef, false);
            return (conversions != null && conversions.Count > 0);
        }

        /// <summary>
        /// Find any user-defined implicit conversion operator to the specified type.
        /// </summary>
        public object FindUserDefinedImplicitConversion(TypeRef targetRef, bool referenceConversionsOnly)
        {
            NamedCodeObjectGroup conversions = FindUserDefinedImplicitConversions(targetRef, referenceConversionsOnly);
            return (conversions != null && conversions.Count == 1 ? conversions[0] : null);
        }

        /// <summary>
        /// Find any user-defined implicit conversion operator to the specified type.
        /// </summary>
        public object FindUserDefinedImplicitConversion(TypeRef targetRef)
        {
            NamedCodeObjectGroup conversions = FindUserDefinedImplicitConversions(targetRef, false);
            return (conversions != null && conversions.Count == 1 ? conversions[0] : null);
        }

        private static void GetConversionFromAndToTypes(object obj, out TypeRefBase fromType, out TypeRefBase toType)
        {
            if (obj is ConversionOperatorDecl)
            {
                ConversionOperatorDecl conversion = (ConversionOperatorDecl)obj;
                fromType = conversion.Parameters[0].EvaluateType();
                toType = conversion.ReturnType.EvaluateType();
            }
            else if (obj is MethodDefinition)
            {
                MethodDefinition conversion = (MethodDefinition)obj;
                fromType = Create(conversion.Parameters[0].ParameterType);
                toType = Create(conversion.ReturnType);
            }
            else if (obj is MethodInfo)
            {
                MethodInfo conversion = (MethodInfo)obj;
                fromType = Create(conversion.GetParameters()[0].ParameterType);
                toType = Create(conversion.ReturnType);
            }
            else
                fromType = toType = null;
        }

        /// <summary>
        /// Determine if type A is "encompassed by" type B.
        /// </summary>
        public static bool IsEncompassedBy(TypeRefBase typeRefA, TypeRefBase typeRefB)
        {
            // If a standard implicit conversion exists from a type A to a type B, and if neither A nor B are
            // interface-types, then A is said to be encompassed by B, and B is said to encompass A.
            return (typeRefA.IsImplicitlyConvertibleTo(typeRefB, true) && !typeRefA.IsInterface && !typeRefB.IsInterface);
        }

        /// <summary>
        /// Find a common type (using implicit conversions) that can represent both specified types.
        /// </summary>
        public static TypeRefBase GetCommonType(TypeRefBase typeRefBase1, TypeRefBase typeRefBase2)
        {
            // Handle either side being null
            if (typeRefBase1 == null)
                return ObjectRef;
            if (typeRefBase2 == null)
                return ObjectRef;

            // Check for equality (the types are the same)
            if (typeRefBase1.IsSameRef(typeRefBase2))
                return (!typeRefBase1.IsConst ? typeRefBase1 : (!typeRefBase2.IsConst ? typeRefBase2 : typeRefBase1.GetTypeWithoutConstant()));

            // Handle either side being a MethodRef or UnresolvedRef
            TypeRef typeRef1 = typeRefBase1 as TypeRef;
            TypeRef typeRef2 = typeRefBase2 as TypeRef;
            if (typeRef1 == null)
                return ObjectRef;
            if (typeRef2 == null)
                return ObjectRef;

            // Check for array ranks, making sure they're the same
            bool hasArrayRanks = typeRef1.HasArrayRanks;
            if (hasArrayRanks)
            {
                // If the ranks don't match, then the common type is 'object'
                if (!typeRef1.HasSameArrayRanks(typeRef2))
                    return ObjectRef;
            }

            // Handle either side being a nullable type
            if (typeRef1.IsNullableType || typeRef2.IsNullableType)
            {
                // Get the common type of the underlying value types, and make a nullable type of it (if it's not 'object')
                TypeRefBase valueType1 = (typeRef1.IsNullableType ? typeRef1.TypeArguments[0].EvaluateType() : typeRef1);
                TypeRefBase valueType2 = (typeRef2.IsNullableType ? typeRef2.TypeArguments[0].EvaluateType() : typeRef2);
                TypeRefBase commonValueType = GetCommonType(valueType1, valueType2);
                return (commonValueType.IsSameRef(ObjectRef) ? commonValueType : CreateNullable(commonValueType));
            }

            TypeRefBase commonType;
            TypeCode typeCode1 = typeRef1.GetTypeCode();
            TypeCode typeCode2 = typeRef2.GetTypeCode();

            // Handle reference types
            if (typeCode1 == TypeCode.Object || typeCode2 == TypeCode.Object)
            {
                // Handle subclasses
                if (typeRef2.IsSubclassOf(typeRef1))
                    commonType = (!typeRef1.IsConst ? typeRef1 : typeRef1.GetTypeWithoutConstant());
                else if (typeRef1.IsSubclassOf(typeRef2))
                    commonType = (!typeRef2.IsConst ? typeRef2 : typeRef2.GetTypeWithoutConstant());
                else
                {
                    // Check for user-defined implicit conversions.  This is really only done here to support the use
                    // of this method by binary operators (such as Add) to evaluate the type of the result, and it's
                    // basically a workaround to the issue of not treating predefined operators as regular methods, and
                    // therefore not doing the method matching logic that does implicit conversions of parameter types
                    // if necessary to choose the proper operator and thus the return type.  Instead, we check for user-
                    // defined implicit conversions here to determine a common type, but this is not a perfect solution.
                    bool from1to2 = typeRef1.UserDefinedImplicitConversionExists(typeRef2);
                    bool from2to1 = typeRef2.UserDefinedImplicitConversionExists(typeRef1);
                    if (from1to2)
                    {
                        // If either conversion is possible, favor one to a primitive (non-reference) type
                        if (from2to1 && typeCode1 != TypeCode.Object)
                            commonType = (!typeRef1.IsConst ? typeRef1 : typeRef1.GetTypeWithoutConstant());
                        else
                            commonType = (!typeRef2.IsConst ? typeRef2 : typeRef2.GetTypeWithoutConstant());
                    }
                    else if (from2to1)
                        commonType = (!typeRef1.IsConst ? typeRef1 : typeRef1.GetTypeWithoutConstant());
                    else
                    {
                        // If no other common type was found, default to 'object'
                        commonType = ObjectRef;
                    }
                }
            }
            else
            {
                // Handle primitive types
                if (typeCode1 >= TypeCode.Char && typeCode1 <= TypeCode.Decimal
                    && typeCode2 >= TypeCode.Char && typeCode2 <= TypeCode.Decimal)
                {
                    // Special handling for constants:

                    // If one side is type 'ulong' and the other is a constant of type 'sbyte', 'short', 'int', or 'long', then
                    // the common type is 'ulong' instead of none (ObjectRef) if the constant is positive.
                    if ((typeCode1 == TypeCode.UInt64 && typeRef2.IsConst
                        && ((typeCode2 == TypeCode.SByte && (sbyte)typeRef2.GetConstantValue() >= 0) || (typeCode2 == TypeCode.Int16 && (short)typeRef2.GetConstantValue() >= 0)
                            || (typeCode2 == TypeCode.Int32 && (int)typeRef2.GetConstantValue() >= 0) || (typeCode2 == TypeCode.Int64 && (long)typeRef2.GetConstantValue() >= 0)))
                        || (typeCode2 == TypeCode.UInt64 && typeRef1.IsConst
                            && ((typeCode1 == TypeCode.SByte && (sbyte)typeRef1.GetConstantValue() >= 0) || (typeCode1 == TypeCode.Int16 && (short)typeRef1.GetConstantValue() >= 0)
                                || (typeCode1 == TypeCode.Int32 && (int)typeRef1.GetConstantValue() >= 0) || (typeCode1 == TypeCode.Int64 && (long)typeRef1.GetConstantValue() >= 0))))
                        commonType = ULongRef;
                    // If one side is type 'uint' and the other is a constant of type 'sbyte', 'short', or 'int', then
                    // the common type is 'uint' instead of 'long' if the constant is positive.
                    else if ((typeCode1 == TypeCode.UInt32 && typeRef2.IsConst
                        && ((typeCode2 == TypeCode.SByte && (sbyte)typeRef2.GetConstantValue() >= 0) || (typeCode2 == TypeCode.Int16 && (short)typeRef2.GetConstantValue() >= 0)
                            || (typeCode2 == TypeCode.Int32 && (int)typeRef2.GetConstantValue() >= 0)))
                        || (typeCode2 == TypeCode.UInt32 && typeRef1.IsConst
                            && ((typeCode1 == TypeCode.SByte && (sbyte)typeRef1.GetConstantValue() >= 0) || (typeCode1 == TypeCode.Int16 && (short)typeRef1.GetConstantValue() >= 0)
                                || (typeCode1 == TypeCode.Int32 && (int)typeRef1.GetConstantValue() >= 0))))
                        commonType = UIntRef;
                    // Handle implicit numeric type conversions
                    else
                        commonType = CommonTypeRefMap[typeCode1 - TypeCode.Char, typeCode2 - TypeCode.Char];
                }
                else
                    commonType = ObjectRef;
            }

            // If the type had array ranks, clone the result and add them on
            if (hasArrayRanks)
            {
                commonType = (TypeRef)commonType.Clone();
                commonType.ArrayRanks = new List<int>(typeRef1.ArrayRanks);
            }

            return commonType;
        }

        #endregion

        #region /* RENDERING */

        public override void AsTextExpression(CodeWriter writer, RenderFlags flags)
        {
            UpdateLineCol(writer, flags);
            AsTextType(writer, _typeArguments, flags);
        }

        public void AsTextType(CodeWriter writer, List<Expression> typeArguments, RenderFlags flags)
        {
            // If it's a nested type, and we have no dot prefix, and the ShowParentTypes flag is set, then
            // render all parent types with appropriate type arguments (this shouldn't occur in display of
            // code, but only when displaying an evaluated type reference, such as in a tooltip).
            // Nova will include all type arguments for any parent types in a reference to a nested type
            // (as .NET Reflection also does).  Such parent type arguments are ignored for display purposes
            // if the TypeRef is displayed in code that includes parent type prefixes or is within the scope
            // of the parent generic type.
            // Also do this for GenericParameters (which are treated as 'nested' by reflection, but not Mono Cecil).
            if (IsNested || IsGenericParameter)
            {
                TypeRefBase typeRefBase = GetDeclaringType();
                if (typeRefBase != null)
                {
                    // Recursively render the parent type minus the type arguments that belong to the current type
                    List<Expression> parentTypeArguments = null;
                    if (typeArguments != null)
                    {
                        int localCount = GetLocalTypeArgumentCount();
                        int parentCount = typeArguments.Count - localCount;
                        if (parentCount > 0)
                        {
                            if (localCount == 0)
                            {
                                parentTypeArguments = typeArguments;
                                typeArguments = null;
                            }
                            else
                            {
                                parentTypeArguments = typeArguments.GetRange(0, parentCount);
                                typeArguments = typeArguments.GetRange(parentCount, localCount);
                            }
                        }
                    }

                    // We must always extract the parent type arguments, but only render the parent types if appropriate
                    if (!flags.HasFlag(RenderFlags.HasDotPrefix) && flags.HasFlag(RenderFlags.ShowParentTypes) && typeRefBase is TypeRef)
                    {
                        // If we're about to render an enclosing type without type parameters, then use the declared
                        // ones by default.  This is necessary for nested Enums, since they are never considered to
                        // be generic types, and won't have any type arguments even if nested inside generic types.
                        // Since an Enum can't be instantiated, the declared type arguments are always appropriate.
                        if (parentTypeArguments == null || parentTypeArguments.Count == 0)
                            parentTypeArguments = ((TypeRef)typeRefBase).GetTypeParametersAsArguments();

                        ((TypeRef)typeRefBase).AsTextType(writer, parentTypeArguments, flags);
                        writer.Write(Dot.ParseToken);
                        flags |= RenderFlags.HasDotPrefix;
                    }
                }
            }

            object reference = GetReferencedType();
            RenderFlags passFlags = flags & ~RenderFlags.Description;

            if (reference is TypeReference)
            {
                // Handle references to TypeDefinitions and GenericParameters
                TypeReference typeReference = (TypeReference)reference;

                //// If we have array ranks, or were requested to suppress them (by NewArray for jagged
                //// arrays), then suppress them in the Type rendering by getting the innermost type.
                //if (HasArrayRanks || flags.HasFlag(RenderFlags.SuppressBrackets))
                //{
                //    while (type.IsArray)
                //        type = type.GetElementType();
                //}

                // If we have type arguments, override any in the Type itself
                if (typeArguments != null)
                {
                    // Render "Nullable<Type>" as "Type?" if optimizations is on *and* there's no "System." prefix
                    if (IsNullableType && !flags.HasFlag(RenderFlags.HasDotPrefix))
                    {
                        // Render the Nullable type argument followed by '?'
                        typeArguments[0].AsText(writer, passFlags & ~RenderFlags.ShowParentTypes);
                        writer.Write(ParseTokenNullable);
                    }
                    else
                    {
                        AsTextTypeReference(writer, typeReference, passFlags | RenderFlags.SuppressTypeArgs);
                        AsTextTypeArguments(writer, typeArguments, flags);
                    }
                }
                else
                {
                    // If the TypeRef has no type arguments, we still want to suppress any on the
                    // type itself - this is valid for bad (incomplete) code.
                    AsTextTypeReference(writer, typeReference, passFlags | RenderFlags.SuppressTypeArgs);
                }
            }
            else if (reference is Type)
            {
                // Handle references to Types
                Type type = (Type)reference;

                // If we have array ranks, or were requested to suppress them (by NewArray for jagged
                // arrays), then suppress them in the Type rendering by getting the innermost type.
                if (HasArrayRanks || flags.HasFlag(RenderFlags.SuppressBrackets))
                {
                    while (type.IsArray)
                        type = type.GetElementType();
                }

                // If we have type arguments, override any in the Type itself
                if (typeArguments != null)
                {
                    // Render "Nullable<Type>" as "Type?" if optimizations is on *and* there's no "System." prefix
                    if (IsNullableType && !flags.HasFlag(RenderFlags.HasDotPrefix))
                    {
                        // Render the Nullable type argument followed by '?'
                        typeArguments[0].AsText(writer, passFlags & ~RenderFlags.ShowParentTypes);
                        writer.Write(ParseTokenNullable);
                    }
                    else
                    {
                        AsTextType(writer, type, passFlags | RenderFlags.SuppressTypeArgs);
                        AsTextTypeArguments(writer, typeArguments, flags);
                    }
                }
                else
                {
                    // If the TypeRef has no type arguments, we still want to suppress any on the
                    // type itself - this is valid for bad (incomplete) code.
                    AsTextType(writer, type, passFlags | RenderFlags.SuppressTypeArgs);
                }
            }
            else
            {
                // Handle references to TypeDecls
                writer.WriteName(Name, flags, true);
                AsTextTypeArguments(writer, typeArguments, flags);
            }

            // Render any array ranks last
            AsTextArrayRanks(writer, passFlags);

            // In description mode, also display any constant value (used for evaluted types of constant expressions)
            if (flags.HasFlag(RenderFlags.Description) && IsConst)
            {
                object constantValue = GetConstantValue();
                bool isHex = (flags.HasFlag(RenderFlags.FormatAsHex) || (constantValue is EnumConstant && ((EnumConstant)constantValue).IsBitFlags));
                Literal.AsTextConstantValue(writer, passFlags, constantValue, isHex, this);
            }
        }

        #endregion
    }

    #region /* ENUM CONSTANT */

    /// <summary>
    /// Represents a constant value of a specified enum type, stored in the underlying type of the enum.
    /// </summary>
    /// <remarks>
    /// This class is necessary because we can't dynamically create an instance of the enum type with the appropriate
    /// value since the type of the enum might be an <see cref="EnumDecl"/>, and we can't rely on being able to create a
    /// <see cref="TypeDefinition"/>/<see cref="Type"/> that represents such a declaration because there could possibly
    /// be compilation errors.
    /// </remarks>
    public class EnumConstant
    {
        #region /* FIELDS */

        /// <summary>
        /// The <see cref="EnumDecl"/> or <see cref="TypeDefinition"/>/<see cref="Type"/> representing the type of the enum.
        /// </summary>
        public TypeRef EnumTypeRef;

        /// <summary>
        /// The constant value of the enum, as an object of the underlying type
        /// </summary>
        public object ConstantValue;

        #endregion

        #region /* CONSTRUCTORS */

        /// <summary>
        /// Create an <see cref="EnumConstant"/>.
        /// </summary>
        public EnumConstant(TypeRef enumTypeRef, object constantValue)
        {
            EnumTypeRef = enumTypeRef;

            // Just in case, default a null constant value to a 0 'int' value
            if (constantValue == null)
                constantValue = 0;
            // If the constant is another EnumConstant, extract it's value
            else if (constantValue is EnumConstant)
                constantValue = ((EnumConstant)constantValue).ConstantValue;

            // Force the constant value to that of the underlying type of the enum if necessary and possible.
            // This is required because the evaluation of constant expressions will promote smaller types to
            // ints, and the enum's underlying type might be smaller.  It's better to do this here rather
            // than inside all of the EvaluateConstants() methods in the various operators.
            ConstantValue = TypeRef.ChangeTypeOfConstant(constantValue, enumTypeRef.GetUnderlyingTypeOfEnum());
        }

        /// <summary>
        /// Create an <see cref="EnumConstant"/>.
        /// </summary>
        public EnumConstant(Type enumType, object constantValue)
            : this(new TypeRef(enumType), constantValue)
        { }

        #endregion

        #region /* PROPERTIES */

        /// <summary>
        /// True if the <see cref="EnumConstant"/> belongs to a bit-flags enum.
        /// </summary>
        public bool IsBitFlags
        {
            get { return EnumTypeRef.IsBitFlagsEnum; }
        }

        #endregion
    }

    #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