Click here to Skip to main content
15,886,095 members
Articles / Programming Languages / C#

CodeDom Assistant

Rate me:
Please Sign up or sign in to vote.
4.84/5 (26 votes)
21 Sep 20074 min read 137.8K   6.6K   82  
Generating CodeDom Code By Parsing C# or VB
// <file>
//     <copyright see="prj:///doc/copyright.txt"/>
//     <license see="prj:///doc/license.txt"/>
//     <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
//     <version>$Revision: 2035 $</version>
// </file>

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;

namespace ICSharpCode.NRefactory.Ast
{
	public class TypeReference : AbstractNode, INullable, ICloneable
	{
		public static readonly TypeReference StructConstraint = new TypeReference("constraint: struct");
		public static readonly TypeReference ClassConstraint = new TypeReference("constraint: class");
		public static readonly TypeReference NewConstraint = new TypeReference("constraint: new");
		
		string type = "";
		string systemType = "";
		int    pointerNestingLevel;
		int[]  rankSpecifier;
		List<TypeReference> genericTypes = new List<TypeReference>();
		bool isGlobal;
		
		#region Static primitive type list
		static Dictionary<string, string> types   = new Dictionary<string, string>();
		static Dictionary<string, string> vbtypes = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
		static Dictionary<string, string> typesReverse   = new Dictionary<string, string>();
		static Dictionary<string, string> vbtypesReverse = new Dictionary<string, string>();
		
		static TypeReference()
		{
			// C# types
			types.Add("bool",    "System.Boolean");
			types.Add("byte",    "System.Byte");
			types.Add("char",    "System.Char");
			types.Add("decimal", "System.Decimal");
			types.Add("double",  "System.Double");
			types.Add("float",   "System.Single");
			types.Add("int",     "System.Int32");
			types.Add("long",    "System.Int64");
			types.Add("object",  "System.Object");
			types.Add("sbyte",   "System.SByte");
			types.Add("short",   "System.Int16");
			types.Add("string",  "System.String");
			types.Add("uint",    "System.UInt32");
			types.Add("ulong",   "System.UInt64");
			types.Add("ushort",  "System.UInt16");
			types.Add("void",    "System.Void");
			
			// VB.NET types
			vbtypes.Add("Boolean", "System.Boolean");
			vbtypes.Add("Byte",    "System.Byte");
			vbtypes.Add("SByte",   "System.SByte");
			vbtypes.Add("Date",	   "System.DateTime");
			vbtypes.Add("Char",    "System.Char");
			vbtypes.Add("Decimal", "System.Decimal");
			vbtypes.Add("Double",  "System.Double");
			vbtypes.Add("Single",  "System.Single");
			vbtypes.Add("Integer", "System.Int32");
			vbtypes.Add("Long",    "System.Int64");
			vbtypes.Add("UInteger","System.UInt32");
			vbtypes.Add("ULong",   "System.UInt64");
			vbtypes.Add("Object",  "System.Object");
			vbtypes.Add("Short",   "System.Int16");
			vbtypes.Add("UShort",  "System.UInt16");
			vbtypes.Add("String",  "System.String");
			
			foreach (KeyValuePair<string, string> pair in types) {
				typesReverse.Add(pair.Value, pair.Key);
			}
			foreach (KeyValuePair<string, string> pair in vbtypes) {
				vbtypesReverse.Add(pair.Value, pair.Key);
			}
		}
		
		/// <summary>
		/// Gets a shortname=>full name dictionary of C# types.
		/// </summary>
		public static IDictionary<string, string> PrimitiveTypesCSharp {
			get { return types; }
		}
		
		/// <summary>
		/// Gets a shortname=>full name dictionary of VB types.
		/// </summary>
		public static IDictionary<string, string> PrimitiveTypesVB {
			get { return vbtypes; }
		}
		
		/// <summary>
		/// Gets a full name=>shortname dictionary of C# types.
		/// </summary>
		public static IDictionary<string, string> PrimitiveTypesCSharpReverse {
			get { return typesReverse; }
		}
		
		/// <summary>
		/// Gets a full name=>shortname dictionary of VB types.
		/// </summary>
		public static IDictionary<string, string> PrimitiveTypesVBReverse {
			get { return vbtypesReverse; }
		}
		
		
		static string GetSystemType(string type)
		{
			if (types == null) return type;
			
			string systemType;
			if (types.TryGetValue(type, out systemType)) {
				return systemType;
			}
			if (vbtypes.TryGetValue(type, out systemType)) {
				return systemType;
			}
			return type;
		}
		#endregion
		
		object ICloneable.Clone()
		{
			return this.Clone();
		}
		
		public virtual TypeReference Clone()
		{
			TypeReference c = new TypeReference(type, systemType);
			CopyFields(this, c);
			return c;
		}
		
		/// <summary>
		/// Copies the pointerNestingLevel, RankSpecifier, GenericTypes and IsGlobal flag
		/// from <paramref name="from"/> to <paramref name="to"/>.
		/// </summary>
		/// <remarks>
		/// If <paramref name="to"/> already contains generics, the new generics are appended to the list.
		/// </remarks>
		protected static void CopyFields(TypeReference from, TypeReference to)
		{
			to.pointerNestingLevel = from.pointerNestingLevel;
			if (from.rankSpecifier != null) {
				to.rankSpecifier = (int[])from.rankSpecifier.Clone();
			}
			foreach (TypeReference r in from.genericTypes) {
				to.genericTypes.Add(r.Clone());
			}
			to.isGlobal = from.isGlobal;
		}
		
		public string Type {
			get {
				return type;
			}
			set {
				Debug.Assert(value != null);
				type = value;
				systemType = GetSystemType(type);
			}
		}
		
		/// <summary>
		/// Removes the last identifier from the type.
		/// e.g. "System.String.Length" becomes "System.String" or
		/// "System.Collections.IEnumerable(of string).Current" becomes "System.Collections.IEnumerable(of string)"
		/// This is used for explicit interface implementation in VB.
		/// </summary>
		public static string StripLastIdentifierFromType(ref TypeReference tr)
		{
			if (tr is InnerClassTypeReference && ((InnerClassTypeReference)tr).Type.IndexOf('.') < 0) {
				string ident = ((InnerClassTypeReference)tr).Type;
				tr = ((InnerClassTypeReference)tr).BaseType;
				return ident;
			} else {
				int pos = tr.Type.LastIndexOf('.');
				if (pos < 0)
					return tr.Type;
				string ident = tr.Type.Substring(pos + 1);
				tr.Type = tr.Type.Substring(0, pos);
				return ident;
			}
		}
		
		public string SystemType {
			get {
				return systemType;
			}
		}
		
		public int PointerNestingLevel {
			get {
				return pointerNestingLevel;
			}
			set {
				pointerNestingLevel = value;
			}
		}
		
		/// <summary>
		/// The rank of the array type.
		/// For "object[]", this is { 0 }; for "object[,]", it is {1}.
		/// For "object[,][,,][]", it is {1, 2, 0}.
		/// For non-array types, this property is null or {}.
		/// </summary>
		public int[] RankSpecifier {
			get {
				return rankSpecifier;
			}
			set {
				rankSpecifier = value;
			}
		}
		
		public List<TypeReference> GenericTypes {
			get {
				return genericTypes;
			}
		}
		
		public bool IsArrayType {
			get {
				return rankSpecifier != null && rankSpecifier.Length > 0;
			}
		}
		
		public static TypeReference CheckNull(TypeReference typeReference)
		{
			return typeReference ?? NullTypeReference.Instance;
		}
		
		public static NullTypeReference Null {
			get {
				return NullTypeReference.Instance;
			}
		}
		
		public virtual bool IsNull {
			get {
				return false;
			}
		}
		
		/// <summary>
		/// Gets/Sets if the type reference had a "global::" prefix.
		/// </summary>
		public bool IsGlobal {
			get {
				return isGlobal;
			}
			set {
				isGlobal = value;
			}
		}
		
		public TypeReference(string type)
		{
			this.Type = type;
		}
		
		public TypeReference(string type, string systemType)
		{
			this.type       = type;
			this.systemType = systemType;
		}
		
		public TypeReference(string type, List<TypeReference> genericTypes) : this(type)
		{
			if (genericTypes != null) {
				this.genericTypes = genericTypes;
			}
		}
		
		public TypeReference(string type, int[] rankSpecifier) : this(type, 0, rankSpecifier)
		{
		}
		
		public TypeReference(string type, int pointerNestingLevel, int[] rankSpecifier) : this(type, pointerNestingLevel, rankSpecifier, null)
		{
		}
		
		public TypeReference(string type, int pointerNestingLevel, int[] rankSpecifier, List<TypeReference> genericTypes)
		{
			Debug.Assert(type != null);
			this.type = type;
			this.systemType = GetSystemType(type);
			this.pointerNestingLevel = pointerNestingLevel;
			this.rankSpecifier = rankSpecifier;
			if (genericTypes != null) {
				this.genericTypes = genericTypes;
			}
		}
		
		protected TypeReference()
		{}
		
		public override object AcceptVisitor(IAstVisitor visitor, object data)
		{
			return visitor.VisitTypeReference(this, data);
		}
		
		public override string ToString()
		{
			StringBuilder b = new StringBuilder(type);
			if (genericTypes != null && genericTypes.Count > 0) {
				b.Append('<');
				for (int i = 0; i < genericTypes.Count; i++) {
					if (i > 0) b.Append(',');
					b.Append(genericTypes[i].ToString());
				}
				b.Append('>');
			}
			if (pointerNestingLevel > 0) {
				b.Append('*', pointerNestingLevel);
			}
			if (IsArrayType) {
				foreach (int rank in rankSpecifier) {
					b.Append('[');
					if (rank < 0)
						b.Append('`', -rank);
					else
						b.Append(',', rank);
					b.Append(']');
				}
			}
			return b.ToString();
		}
		
		public static bool AreEqualReferences(TypeReference a, TypeReference b)
		{
			if (a == b) return true;
			if (a == null || b == null) return false;
			if (a is InnerClassTypeReference) a = ((InnerClassTypeReference)a).CombineToNormalTypeReference();
			if (b is InnerClassTypeReference) b = ((InnerClassTypeReference)b).CombineToNormalTypeReference();
			if (a.systemType != b.systemType) return false;
			if (a.pointerNestingLevel != b.pointerNestingLevel) return false;
			if (a.IsArrayType != b.IsArrayType) return false;
			if (a.IsArrayType) {
				if (a.rankSpecifier.Length != b.rankSpecifier.Length) return false;
				for (int i = 0; i < a.rankSpecifier.Length; i++) {
					if (a.rankSpecifier[i] != b.rankSpecifier[i]) return false;
				}
			}
			if (a.genericTypes.Count != b.genericTypes.Count) return false;
			for (int i = 0; i < a.genericTypes.Count; i++) {
				if (!AreEqualReferences(a.genericTypes[i], b.genericTypes[i]))
					return false;
			}
			return true;
		}
	}

	public class NullTypeReference : TypeReference
	{
		static NullTypeReference nullTypeReference = new NullTypeReference();
		public override bool IsNull {
			get {
				return true;
			}
		}
		public override object AcceptVisitor(IAstVisitor visitor, object data)
		{
			return null;
		}
		public static NullTypeReference Instance {
			get {
				return nullTypeReference;
			}
		}
		NullTypeReference() {}
		public override string ToString()
		{
			return String.Format("[NullTypeReference]");
		}
	}

	/// <summary>
	/// We need this special type reference for cases like
	/// OuterClass(Of T1).InnerClass(Of T2) (in expression or type context)
	/// or Dictionary(Of String, NamespaceStruct).KeyCollection (in type context, otherwise it's a
	/// MemberReferenceExpression)
	/// </summary>
	public class InnerClassTypeReference: TypeReference
	{
		TypeReference baseType;
		
		public TypeReference BaseType {
			get { return baseType; }
			set { baseType = value; }
		}
		
		public override TypeReference Clone()
		{
			InnerClassTypeReference c = new InnerClassTypeReference(baseType.Clone(), Type, GenericTypes);
			CopyFields(this, c);
			return c;
		}
		
		public InnerClassTypeReference(TypeReference outerClass, string innerType, List<TypeReference> innerGenericTypes)
			: base(innerType, innerGenericTypes)
		{
			this.baseType = outerClass;
		}
		
		public override object AcceptVisitor(IAstVisitor visitor, object data)
		{
			return visitor.VisitInnerClassTypeReference(this, data);
		}
		
		/// <summary>
		/// Creates a type reference where all type parameters are specified for the innermost class.
		/// Namespace.OuterClass(of string).InnerClass(of integer).InnerInnerClass
		/// becomes Namespace.OuterClass.InnerClass.InnerInnerClass(of string, integer)
		/// </summary>
		public TypeReference CombineToNormalTypeReference()
		{
			TypeReference tr = (baseType is InnerClassTypeReference)
				? ((InnerClassTypeReference)baseType).CombineToNormalTypeReference()
				: baseType.Clone();
			CopyFields(this, tr);
			tr.Type += "." + Type;
			return tr;
		}
		
		public override string ToString()
		{
			return "[InnerClassTypeReference: (" + baseType.ToString() + ")." + base.ToString() + "]";
		}
	}
}

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions