context: // Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
  // 
  // Permission is hereby granted, free of charge, to any person obtaining a copy of this
  // software and associated documentation files (the "Software"), to deal in the Software
  // without restriction, including without limitation the rights to use, copy, modify, merge,
  // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  // to whom the Software is furnished to do so, subject to the following conditions:
  // 
  // The above copyright notice and this permission notice shall be included in all copies or
  // substantial portions of the Software.
  // 
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  // DEALINGS IN THE SOFTWARE.
  
  using System;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.Linq;
  using System.Runtime.CompilerServices;
  using System.Runtime.InteropServices;
  using dnlib.DotNet;
  using dnSpy.Decompiler;
  using dnSpy.NRefactory;
  using ICSharpCode.Decompiler.Ast.Transforms;
  using ICSharpCode.Decompiler.ILAst;
  using ICSharpCode.NRefactory.CSharp;
  using ICSharpCode.NRefactory.Utils;
  
  namespace ICSharpCode.Decompiler.Ast {
  	using Ast = ICSharpCode.NRefactory.CSharp;
  	using VarianceModifier = ICSharpCode.NRefactory.TypeSystem.VarianceModifier;
  
  	[Flags]
  	public enum ConvertTypeOptions
  	{
  		None = 0,
  		IncludeNamespace = 1,
  		IncludeTypeParameterDefinitions = 2,
  		DoNotUsePrimitiveTypeNames = 4
  	}
  	
  	public class AstBuilder
  	{
  		DecompilerContext context;
  		SyntaxTree syntaxTree = new SyntaxTree();
  		Dictionary<string, NamespaceDeclaration> astNamespaces = new Dictionary<string, NamespaceDeclaration>();
  		bool transformationsHaveRun;
  		
  		public AstBuilder(DecompilerContext context)
  		{
  			if (context == null)
  				throw new ArgumentNullException("context");
  			this.context = context;
  			this.DecompileMethodBodies = true;
  		}
  		
  		public static bool MemberIsHidden(IMemberRef member, DecompilerSettings settings)
  		{
  			if (settings.ForceShowAllMembers)
  				return false;
  			MethodDef method = member as MethodDef;
  			if (method != null) {
  				if (method.IsGetter || method.IsSetter || method.IsAddOn || method.IsRemoveOn)
  					return true;
  				if (settings.AnonymousMethods && method.HasGeneratedName() && method.IsCompilerGenerated())
  					return true;
  			}
  
  			TypeDef type = member as TypeDef;
  			if (type != null) {
  				if (type.DeclaringType != null) {
  					if (settings.AnonymousMethods && IsClosureType(type))
  						return true;
  					if (settings.YieldReturn && YieldReturnDecompiler.IsCompilerGeneratorEnumerator(type))
  						return true;
  					if (settings.AsyncAwait && AsyncDecompiler.IsCompilerGeneratedStateMachine(type))
  						return true;
  				} else if (type.IsCompilerGenerated()) {
  					if (type.Name.StartsWith("<PrivateImplementationDetails>", StringComparison.Ordinal))
  						return true;
  					if (type.IsAnonymousType())
  						return true;
  				}
  			}
  			
  			FieldDef field = member as FieldDef;
  			if (field != null) {
  				if (field.IsCompilerGenerated()) {
  					if (settings.AnonymousMethods && IsAnonymousMethodCacheField(field))
  						return true;
  					if (settings.AutomaticProperties && IsAutomaticPropertyBackingField(field))
  						return true;
  					if (settings.SwitchStatementOnString && IsSwitchOnStringCache(field))
  						return true;
  				}
  				// event-fields are not [CompilerGenerated]
  				if (settings.AutomaticEvents && field.DeclaringType.Events.Any(ev => ev.Name == field.Name))
  					return true;
  			}
  			
  			return false;
  		}
  
  		static bool IsSwitchOnStringCache(FieldDef field)
  		{
  			return field.Name.StartsWith("<>f__switch", StringComparison.Ordinal);
  		}
  
  		static bool IsAutomaticPropertyBackingField(FieldDef field)
  		{
  			return field.HasGeneratedName() && field.Name.EndsWith("BackingField", StringComparison.Ordinal);
  		}
  
  		static bool IsAnonymousMethodCacheField(FieldDef field)
  		{
  			return field.Name.StartsWith("CS$<>", StringComparison.Ordinal) || field.Name.StartsWith("<>f__am", StringComparison.Ordinal);
  		}
  
  		static bool IsClosureType(TypeDef type)
  		{
  			return type.HasGeneratedName() && type.IsCompilerGenerated() && (type.Name.Contains("DisplayClass") || type.Name.Contains("AnonStorey"));
  		}
  		
  		/// <summary>
  		/// Runs the C# transformations on the compilation unit.
  		/// </summary>
  		public void RunTransformations()
  		{
  			RunTransformations(null);
  		}
  		
  		public void RunTransformations(Predicate<IAstTransform> transformAbortCondition)
  		{
  			TransformationPipeline.RunTransformationsUntil(syntaxTree, transformAbortCondition, context);
  			transformationsHaveRun = true;
  		}
  		
  		/// <summary>
  		/// Gets the abstract source tree.
  		/// </summary>
  		public SyntaxTree SyntaxTree {
  			get { return syntaxTree; }
  		}
  		
  		/// <summary>
  		/// Generates C# code from the abstract source tree.
  		/// </summary>
  		/// <remarks>This method adds ParenthesizedExpressions into the AST, and will run transformations if <see cref="RunTransformations"/> was not called explicitly</remarks>
  		public void GenerateCode(ITextOutput output)
  		{
  			if (!transformationsHaveRun)
  				RunTransformations();
  			
  			syntaxTree.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true });
  			var outputFormatter = new TextTokenWriter(output, context) { FoldBraces = false };
  			var formattingPolicy = context.Settings.CSharpFormattingOptions;
  			syntaxTree.AcceptVisitor(new CSharpOutputVisitor(outputFormatter, formattingPolicy, context.CancellationToken));
  		}
  		
  		public void AddAssembly(AssemblyDef assemblyDefinition, bool onlyAssemblyLevel = false)
  		{
  			AddAssembly(assemblyDefinition.ManifestModule, onlyAssemblyLevel, true, true);
  		}
  
  		public void AddAssembly(ModuleDef moduleDefinition, bool onlyAssemblyLevel, bool decompileAsm, bool decompileMod)
  		{
  			if (decompileAsm && moduleDefinition.Assembly != null && moduleDefinition.Assembly.Version != null) {
  				syntaxTree.AddChild(
  					new AttributeSection {
  						AttributeTarget = "assembly",
  						Attributes = {
  							new NRefactory.CSharp.Attribute {
  								Type = new SimpleType("AssemblyVersion")
  									.WithAnnotation(moduleDefinition.CorLibTypes.GetTypeRef(
  										"System.Reflection", "AssemblyVersionAttribute")),
  								Arguments = {
  									new PrimitiveExpression(moduleDefinition.Assembly.Version.ToString())
  								}
  							}
  						}
  					}, EntityDeclaration.AttributeRole);
  			}
  			
  			if (decompileAsm && moduleDefinition.Assembly != null) {
  				ConvertCustomAttributes(syntaxTree, moduleDefinition.Assembly, "assembly");
  				ConvertSecurityAttributes(syntaxTree, moduleDefinition.Assembly, "assembly");
  			}
  			if (decompileMod) {
  				ConvertCustomAttributes(syntaxTree, moduleDefinition, "module");
  				AddTypeForwarderAttributes(syntaxTree, moduleDefinition, "assembly");
  			}
  			
  			if (decompileMod && !onlyAssemblyLevel) {
  				foreach (TypeDef typeDef in moduleDefinition.Types) {
  					// Skip the <Module> class
  					if (typeDef.IsGlobalModuleType) continue;
  					// Skip any hidden types
  					if (AstBuilder.MemberIsHidden(typeDef, context.Settings))
  						continue;
  
  					AddType(typeDef);
  				}
  			}
  		}
  		
  		void AddTypeForwarderAttributes(SyntaxTree astCompileUnit, ModuleDef module, string target)
  		{
  			if (!module.HasExportedTypes)
  				return;
  			foreach (ExportedType type in module.ExportedTypes) {
  				if (type.MovedToAnotherAssembly) {
  					var forwardedType = CreateTypeOfExpression(type.ToTypeRef());
  					astCompileUnit.AddChild(
  						new AttributeSection {
  							AttributeTarget = target,
  							Attributes = {
  								new NRefactory.CSharp.Attribute {
  									Type = new SimpleType("TypeForwardedTo")
  										.WithAnnotation(module.CorLibTypes.GetTypeRef(
  											"System.Runtime.CompilerServices", "TypeForwardedToAttribute")),
  									Arguments = { forwardedType }
  								}
  							}
  						}, EntityDeclaration.AttributeRole);
  				}
  			}
  		}
  		
  		NamespaceDeclaration GetCodeNamespace(string name)
  		{
  			if (string.IsNullOrEmpty(name)) {
  				return null;
  			}
  			if (astNamespaces.ContainsKey(name)) {
  				return astNamespaces[name];
  			} else {
  				// Create the namespace
  				NamespaceDeclaration astNamespace = new NamespaceDeclaration { Name = name };
  				syntaxTree.Members.Add(astNamespace);
  				astNamespaces[name] = astNamespace;
  				return astNamespace;
  			}
  		}
  
  		void AddComment(AstNode node, IMemberDef member)
  		{
  			if (!this.context.Settings.ShowTokenAndRvaComments)
  				return;
  			uint rva;
  			long fileOffset;
  			member.GetRVA(out rva, out fileOffset);
  
  			var creator = new CommentReferencesCreator();
  			creator.AddText(" Token: ");
  			creator.AddReference(string.Format("0x{0:X8}", member.MDToken.Raw), new TokenReference(member));
  			creator.AddText(string.Format(" RID: {0}", member.MDToken.Rid));
  			if (rva != 0) {
  				var mod = member.Module;
  				var filename = mod == null ? null : mod.Location;
  				creator.AddText(" RVA: ");
  				creator.AddReference(string.Format("0x{0:X8}", rva), new AddressReference(filename, true, rva, 0));
  				creator.AddText(" File Offset: ");
  				creator.AddReference(string.Format("0x{0:X8}", fileOffset), new AddressReference(filename, false, (ulong)fileOffset, 0));
  			}
  
  			var cmt = new Comment(creator.Text);
  			cmt.References = creator.CommentReferences;
  			node.InsertChildAfter(null, cmt, Roles.Comment);
  		}
  		
  		public void AddType(TypeDef typeDef)
  		{
  			var astType = CreateType(typeDef);
  			NamespaceDeclaration astNS = GetCodeNamespace(typeDef.Namespace);
  			if (astNS != null) {
  				astNS.Members.Add(astType);
  			} else {
  				syntaxTree.Members.Add(astType);
  			}
  		}
  		
  		public void AddMethod(MethodDef method)
  		{
  			AstNode node = method.IsConstructor ? (AstNode)CreateConstructor(method) : CreateMethod(method);
  			syntaxTree.Members.Add(node);
  		}
  
  		public void AddProperty(PropertyDef property)
  		{
  			syntaxTree.Members.Add(CreateProperty(property));
  		}
  		
  		public void AddField(FieldDef field)
  		{
  			syntaxTree.Members.Add(CreateField(field));
  		}
  		
  		public void AddEvent(EventDef ev)
  		{
  			syntaxTree.Members.Add(CreateEvent(ev));
  		}
  		
  		/// <summary>
  		/// Creates the AST for a type definition.
  		/// </summary>
  		/// <param name="typeDef"></param>
  		/// <returns>TypeDeclaration or DelegateDeclaration.</returns>
  		public EntityDeclaration CreateType(TypeDef typeDef)
  		{
  			// create type
  			TypeDef oldCurrentType = context.CurrentType;
  			context.CurrentType = typeDef;
  			TypeDeclaration astType = new TypeDeclaration();
  			ConvertAttributes(astType, typeDef);
  			astType.AddAnnotation(typeDef);
  			astType.Modifiers = ConvertModifiers(typeDef);
  			astType.NameToken = Identifier.Create(CleanName(typeDef.Name)).WithAnnotation(typeDef);
  			
  			if (typeDef.IsEnum) {  // NB: Enum is value type
  				astType.ClassType = ClassType.Enum;
  				astType.Modifiers &= ~Modifiers.Sealed;
  			} else if (DnlibExtensions.IsValueType(typeDef)) {
  				astType.ClassType = ClassType.Struct;
  				astType.Modifiers &= ~Modifiers.Sealed;
  			} else if (typeDef.IsInterface) {
  				astType.ClassType = ClassType.Interface;
  				astType.Modifiers &= ~Modifiers.Abstract;
  			} else {
  				astType.ClassType = ClassType.Class;
  			}
  			
  			IEnumerable<GenericParam> genericParameters = typeDef.GenericParameters;
  			if (typeDef.DeclaringType != null && typeDef.DeclaringType.HasGenericParameters)
  				genericParameters = genericParameters.Skip(typeDef.DeclaringType.GenericParameters.Count);
  			astType.TypeParameters.AddRange(MakeTypeParameters(genericParameters));
  			astType.Constraints.AddRange(MakeConstraints(genericParameters));
  			
  			EntityDeclaration result = astType;
  			if (typeDef.IsEnum) {
  				long expectedEnumMemberValue = 0;
  				bool forcePrintingInitializers = IsFlagsEnum(typeDef);
  				var enumType = typeDef.Fields.FirstOrDefault(f => !f.IsStatic);
  				foreach (FieldDef field in typeDef.Fields) {
  					if (!field.IsStatic) {
  						// the value__ field
  						if (!new SigComparer().Equals(field.FieldType, typeDef.Module.CorLibTypes.Int32)) {
  							astType.AddChild(ConvertType(field.FieldType), Roles.BaseType);
  						}
  					} else {
  						EnumMemberDeclaration enumMember = new EnumMemberDeclaration();
  						ConvertCustomAttributes(enumMember, field);
  						enumMember.AddAnnotation(field);
  						enumMember.NameToken = Identifier.Create(CleanName(field.Name)).WithAnnotation(field);
  						var constant = field.Constant == null ? null : field.Constant.Value;
  						TypeCode c = constant == null ? TypeCode.Empty : Type.GetTypeCode(constant.GetType());
  						if (c < TypeCode.Char || c > TypeCode.Decimal)
  							continue;
  						long memberValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, constant, false);
  						if (forcePrintingInitializers || memberValue != expectedEnumMemberValue) {
  							enumMember.AddChild(new PrimitiveExpression(ConvertConstant(enumType == null ? null : enumType.FieldSig.GetFieldType(), constant)), EnumMemberDeclaration.InitializerRole);
  						}
  						expectedEnumMemberValue = memberValue + 1;
  						astType.AddChild(enumMember, Roles.TypeMemberRole);
  						AddComment(enumMember, field);
  					}
  				}
  			} else if (IsNormalDelegate(typeDef)) {
  				DelegateDeclaration dd = new DelegateDeclaration();
  				dd.Modifiers = astType.Modifiers & ~Modifiers.Sealed;
  				dd.NameToken = (Identifier)astType.NameToken.Clone();
  				dd.AddAnnotation(typeDef);
  				astType.Attributes.MoveTo(dd.Attributes);
  				astType.TypeParameters.MoveTo(dd.TypeParameters);
  				astType.Constraints.MoveTo(dd.Constraints);
  				foreach (var m in typeDef.Methods) {
  					if (m.Name == "Invoke") {
  						dd.ReturnType = ConvertType(m.ReturnType, m.Parameters.ReturnParameter.ParamDef);
  						dd.Parameters.AddRange(MakeParameters(m));
  						ConvertAttributes(dd, m.Parameters.ReturnParameter, m.Module);
  						AddComment(dd, m);
  					}
  				}
  				AddComment(dd, typeDef);
  				result = dd;
  			} else {
  				// Base type
  				if (typeDef.BaseType != null && !DnlibExtensions.IsValueType(typeDef) && typeDef.BaseType.FullName != "System.Object") {
  					astType.AddChild(ConvertType(typeDef.BaseType), Roles.BaseType);
  				}
  				foreach (var i in typeDef.Interfaces)
  					astType.AddChild(ConvertType(i.Interface), Roles.BaseType);
  				
  				AddTypeMembers(astType, typeDef);
  
  				if (astType.Members.OfType<IndexerDeclaration>().Any(idx => idx.PrivateImplementationType.IsNull)) {
  					// Remove the [DefaultMember] attribute if the class contains indexers
  					foreach (AttributeSection section in astType.Attributes) {
  						foreach (Ast.Attribute attr in section.Attributes) {
  							ITypeDefOrRef tr = attr.Type.Annotation<ITypeDefOrRef>();
  							if (tr != null && tr.Name == "DefaultMemberAttribute" && tr.Namespace == "System.Reflection") {
  								attr.Remove();
  							}
  						}
  						if (section.Attributes.Count == 0)
  							section.Remove();
  					}
  				}
  			}
  
  			AddComment(astType, typeDef);
  			context.CurrentType = oldCurrentType;
  			return result;
  		}
  
  		static bool IsNormalDelegate(TypeDef td)
  		{
  			if (td.BaseType == null || td.BaseType.FullName != "System.MulticastDelegate")
  				return false;
  
  			if (td.HasFields)
  				return false;
  			if (td.HasProperties)
  				return false;
  			if (td.HasEvents)
  				return false;
  			if (td.Methods.Any(m => m.Body != null))
  				return false;
  
  			return true;
  		}
  
  		internal static string CleanName(string name)
  		{
  			int pos = name.LastIndexOf('`');
  			if (pos >= 0)
  				name = name.Substring(0, pos);
  			// Could be a compiler-generated name, eg. "<.ctor>b__0_0"
  			if (name.Length == 0 || name[0] != '<') {
  				pos = name.LastIndexOf('.');
  				if (pos >= 0)
  					name = name.Substring(pos + 1);
  			}
  			return name;
  		}
  
  		#region Create TypeOf Expression
  		/// <summary>
  		/// Creates a typeof-expression for the specified type.
  		/// </summary>
  		public static TypeOfExpression CreateTypeOfExpression(ITypeDefOrRef type)
  		{
  			return new TypeOfExpression(AddEmptyTypeArgumentsForUnboundGenerics(ConvertType(type)));
  		}
  		
  		static AstType AddEmptyTypeArgumentsForUnboundGenerics(AstType type)
  		{
  			ITypeDefOrRef typeRef = type.Annotation<ITypeDefOrRef>();
  			if (typeRef == null)
  				return type;
  			TypeDef typeDef = typeRef.ResolveTypeDef(); // need to resolve to figure out the number of type parameters
  			if (typeDef == null || !typeDef.HasGenericParameters)
  				return type;
  			SimpleType sType = type as SimpleType;
  			MemberType mType = type as MemberType;
  			if (sType != null) {
  				while (typeDef.GenericParameters.Count > sType.TypeArguments.Count) {
  					sType.TypeArguments.Add(new SimpleType("").WithAnnotation(TextTokenType.TypeGenericParameter).WithAnnotation(SimpleType.DummyTypeGenericParam));
  				}
  			}
  			
  			if (mType != null) {
  				AddEmptyTypeArgumentsForUnboundGenerics(mType.Target);
  				
  				int outerTypeParamCount = typeDef.DeclaringType == null ? 0 : typeDef.DeclaringType.GenericParameters.Count;
  				
  				while (typeDef.GenericParameters.Count - outerTypeParamCount > mType.TypeArguments.Count) {
  					mType.TypeArguments.Add(new SimpleType("").WithAnnotation(TextTokenType.TypeGenericParameter).WithAnnotation(SimpleType.DummyTypeGenericParam));
  				}
  			}
  			
  			return type;
  		}
  		#endregion
  		
  		#region Convert Type Reference
  		/// <summary>
  		/// Converts a type reference.
  		/// </summary>
  		/// <param name="type">The type reference that should be converted into
  		/// a type system type reference.</param>
  		/// <param name="typeAttributes">Attributes associated with the type reference.
  		/// This is used to support the 'dynamic' type.</param>
  		public static AstType ConvertType(ITypeDefOrRef type, IHasCustomAttribute typeAttributes = null, ConvertTypeOptions options = ConvertTypeOptions.None)
  		{
  			int typeIndex = 0;
  			return ConvertType(type, typeAttributes, ref typeIndex, options, 0);
  		}
  
  		/// <summary>
  		/// Converts a type reference.
  		/// </summary>
  		/// <param name="type">The type reference that should be converted into
  		/// a type system type reference.</param>
  		/// <param name="typeAttributes">Attributes associated with the type reference.
  		/// This is used to support the 'dynamic' type.</param>
  		public static AstType ConvertType(TypeSig type, IHasCustomAttribute typeAttributes = null, ConvertTypeOptions options = ConvertTypeOptions.None)
  		{
  			int typeIndex = 0;
  			return ConvertType(type, typeAttributes, ref typeIndex, options, 0);
  		}
  
  		const int MAX_CONVERTTYPE_DEPTH = 50;
  		static AstType ConvertType(TypeSig type, IHasCustomAttribute typeAttributes, ref int typeIndex, ConvertTypeOptions options, int depth)
  		{
  			if (depth++ > MAX_CONVERTTYPE_DEPTH)
  				return AstType.Null;
  			type = type.RemovePinnedAndModifiers();
  			if (type == null) {
  				return AstType.Null;
  			}
  			
  			if (type is ByRefSig) {
  				typeIndex++;
  				// by reference type cannot be represented in C#; so we'll represent it as a pointer instead
  				return ConvertType((type as ByRefSig).Next, typeAttributes, ref typeIndex, options, depth)
  					.MakePointerType();
  			} else if (type is PtrSig) {
  				typeIndex++;
  				return ConvertType((type as PtrSig).Next, typeAttributes, ref typeIndex, options, depth)
  					.MakePointerType();
  			} else if (type is ArraySigBase) {
  				typeIndex++;
  				return ConvertType((type as ArraySigBase).Next, typeAttributes, ref typeIndex, options, depth)
  					.MakeArrayType((int)(type as ArraySigBase).Rank);
  			} else if (type is GenericInstSig) {
  				GenericInstSig gType = (GenericInstSig)type;
  				if (gType.GenericType != null && gType.GenericType.Namespace == "System" && gType.GenericType.TypeName == "Nullable`1" && gType.GenericArguments.Count == 1) {
  					typeIndex++;
  					return new ComposedType {
  						BaseType = ConvertType(gType.GenericArguments[0], typeAttributes, ref typeIndex, options, depth),
  						HasNullableSpecifier = true
  					};
  				}
  				AstType baseType = ConvertType(gType.GenericType == null ? null : gType.GenericType.TypeDefOrRef, typeAttributes, ref typeIndex, options & ~ConvertTypeOptions.IncludeTypeParameterDefinitions, depth);
  				List<AstType> typeArguments = new List<AstType>();
  				foreach (var typeArgument in gType.GenericArguments) {
  					typeIndex++;
  					typeArguments.Add(ConvertType(typeArgument, typeAttributes, ref typeIndex, options, depth));
  				}
  				ApplyTypeArgumentsTo(baseType, typeArguments);
  				return baseType;
  			} else if (type is GenericSig) {
  				var sig = (GenericSig)type;
  				var simpleType = new SimpleType(sig.TypeName).WithAnnotation(sig.GenericParam).WithAnnotation(type);
  				simpleType.IdentifierToken.WithAnnotation(sig.GenericParam).WithAnnotation(type);
  				return simpleType;
  			} else if (type is TypeDefOrRefSig) {
  				return ConvertType(((TypeDefOrRefSig)type).TypeDefOrRef, typeAttributes, ref typeIndex, options, depth);
  			} else
  				return ConvertType(type.ToTypeDefOrRef(), typeAttributes, ref typeIndex, options, depth);
  		}
  
  		static AstType ConvertType(ITypeDefOrRef type, IHasCustomAttribute typeAttributes, ref int typeIndex, ConvertTypeOptions options, int depth)
  		{
  			if (depth++ > MAX_CONVERTTYPE_DEPTH || type == null)
  				return AstType.Null;
  
  			var ts = type as TypeSpec;
  			if (ts != null && !(ts.TypeSig is FnPtrSig))
  				return ConvertType(ts.TypeSig, typeAttributes, ref typeIndex, options, depth);
  
  			if (type.DeclaringType != null) {
  				AstType typeRef = ConvertType(type.DeclaringType, typeAttributes, ref typeIndex, options & ~ConvertTypeOptions.IncludeTypeParameterDefinitions, depth);
  				string namepart = ICSharpCode.NRefactory.TypeSystem.ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name);
  				MemberType memberType = new MemberType { Target = typeRef, MemberNameToken = Identifier.Create(namepart).WithAnnotation(type) };
  				memberType.AddAnnotation(type);
  				if ((options & ConvertTypeOptions.IncludeTypeParameterDefinitions) == ConvertTypeOptions.IncludeTypeParameterDefinitions) {
  					AddTypeParameterDefininitionsTo(type, memberType);
  				}
  				return memberType;
  			} else {
  				string ns = type.Namespace ?? string.Empty;
  				string name = type.Name;
  				if (ts != null)
  					name = DnlibExtensions.GetFnPtrName(ts.TypeSig as FnPtrSig);
  				if (name == null)
  					throw new InvalidOperationException("type.Name returned null. Type: " + type.ToString());
  				
  				if (name == "Object" && ns == "System" && HasDynamicAttribute(typeAttributes, typeIndex)) {
  					return new PrimitiveType("dynamic");
  				} else {
  					if (ns == "System") {
  						if ((options & ConvertTypeOptions.DoNotUsePrimitiveTypeNames)
  							!= ConvertTypeOptions.DoNotUsePrimitiveTypeNames) {
  							switch (name) {
  								case "SByte":
  									return new PrimitiveType("sbyte").WithAnnotation(type);
  								case "Int16":
  									return new PrimitiveType("short").WithAnnotation(type);
  								case "Int32":
  									return new PrimitiveType("int").WithAnnotation(type);
  								case "Int64":
  									return new PrimitiveType("long").WithAnnotation(type);
  								case "Byte":
  									return new PrimitiveType("byte").WithAnnotation(type);
  								case "UInt16":
  									return new PrimitiveType("ushort").WithAnnotation(type);
  								case "UInt32":
  									return new PrimitiveType("uint").WithAnnotation(type);
  								case "UInt64":
  									return new PrimitiveType("ulong").WithAnnotation(type);
  								case "String":
  									return new PrimitiveType("string").WithAnnotation(type);
  								case "Single":
  									return new PrimitiveType("float").WithAnnotation(type);
  								case "Double":
  									return new PrimitiveType("double").WithAnnotation(type);
  								case "Decimal":
  
gt: 									return new PrimitiveType("decimal").WithAnnotation(type);