New test.
[mono.git] / mcs / class / System / System.CodeDom / CodeTypeReference.cs
index 7a955d8868b3bb4ff44debf1c186ed22fbae14b7..a61df458f7393e363d4053106b299a7d58780265 100644 (file)
 //
 
 using System.Runtime.InteropServices;
+using System.Text;
 
 namespace System.CodeDom
 {
        [Serializable]
        [ClassInterface(ClassInterfaceType.AutoDispatch)]
        [ComVisible(true)]
-       public class CodeTypeReference
-               : CodeObject
+       public class CodeTypeReference : CodeObject
        {
                private string baseType;
-               private CodeTypeReference arrayType;
-               private int rank;
+               private CodeTypeReference arrayElementType;
+               private int arrayRank;
+               private bool isInterface;
+               //bool needsFixup;
 
 #if NET_2_0
                CodeTypeReferenceCollection typeArguments;
-               CodeTypeReferenceOptions codeTypeReferenceOption;
+               CodeTypeReferenceOptions referenceOptions;
 #endif
 
                //
                // Constructors
                //
-               public CodeTypeReference( string baseType )
-               {
-                       if (baseType.Length == 0) {
-                               this.baseType = typeof (void).FullName;
-                               return;
-                       }
-
-                       int array_start = baseType.LastIndexOf ('[');
-                       if (array_start == -1) {
-                               this.baseType = baseType;
-                               return;
-                       }
-                       string[] args = baseType.Split (',');
 
-                       int array_end = baseType.LastIndexOf (']');
+#if NET_2_0
+               public CodeTypeReference ()
+               {
+               }
+#endif
 
 #if NET_2_0
-                       if ((array_end - array_start) != args.Length) {
-                               arrayType = new CodeTypeReference (baseType.Substring (0, array_start));
-                               array_start++;
-                               TypeArguments.Add (new CodeTypeReference (baseType.Substring (array_start, array_end - array_start)));
-                       } else
+               [MonoTODO("We should parse basetype from right to left in 2.0 profile.")]
 #endif
-                               arrayType = new CodeTypeReference (baseType.Substring (0, array_start), args.Length);
+               public CodeTypeReference (string baseType)
+               {
+                       Parse (baseType);
                }
-               
-               public CodeTypeReference( Type baseType )
+
+#if NET_2_0
+               [MonoTODO("We should parse basetype from right to left in 2.0 profile.")]
+#endif
+               public CodeTypeReference (Type baseType)
                {
+#if NET_2_0
+                       if (baseType == null) {
+                               throw new ArgumentNullException ("baseType");
+                       }
+
+                       if (baseType.IsGenericParameter) {
+                               this.baseType = baseType.Name;
+                               this.referenceOptions = CodeTypeReferenceOptions.GenericTypeParameter;
+                       }
+                       else if (baseType.IsGenericTypeDefinition)
+                               this.baseType = baseType.FullName;
+                       else if (baseType.IsGenericType) {
+                               this.baseType = baseType.GetGenericTypeDefinition ().FullName;
+                               foreach (Type arg in baseType.GetGenericArguments ()) {
+                                       if (arg.IsGenericParameter)
+                                               TypeArguments.Add (new CodeTypeReference (new CodeTypeParameter (arg.Name)));
+                                       else
+                                               TypeArguments.Add (new CodeTypeReference (arg));
+                               }
+                       }
+                       else
+#endif
                        if (baseType.IsArray) {
-                               this.rank = baseType.GetArrayRank ();
-                               this.arrayType = new CodeTypeReference (baseType.GetElementType ());
-                               this.baseType = arrayType.BaseType;
-                               return;
+                               this.arrayRank = baseType.GetArrayRank ();
+                               this.arrayElementType = new CodeTypeReference (baseType.GetElementType ());
+                               this.baseType = arrayElementType.BaseType;
+                       } else {
+                               Parse (baseType.FullName);
                        }
-                       this.baseType = baseType.FullName;
+                       this.isInterface = baseType.IsInterface;
                }
 
-               public CodeTypeReference( CodeTypeReference arrayType, int rank )
+               public CodeTypeReference( CodeTypeReference arrayElementType, int arrayRank )
                {
                        this.baseType = null;
-                       this.rank = rank;
-                       this.arrayType = arrayType;
+                       this.arrayRank = arrayRank;
+                       this.arrayElementType = arrayElementType;
                }
 
-               public CodeTypeReference( string baseType, int rank )
-                       : this (new CodeTypeReference (baseType), rank)
+#if NET_2_0
+               [MonoTODO("We should parse basetype from right to left in 2.0 profile.")]
+#endif
+               public CodeTypeReference( string baseType, int arrayRank )
+                       : this (new CodeTypeReference (baseType), arrayRank)
                {
                }
-                       
+
 #if NET_2_0
                public CodeTypeReference( CodeTypeParameter typeParameter ) :
                        this (typeParameter.Name)
                {
+                       this.referenceOptions = CodeTypeReferenceOptions.GenericTypeParameter;
                }
 
-               public CodeTypeReference( string typeName, CodeTypeReferenceOptions codeTypeReferenceOption ) :
+               public CodeTypeReference( string typeName, CodeTypeReferenceOptions referenceOptions ) :
                        this (typeName)
                {
-                       this.codeTypeReferenceOption = codeTypeReferenceOption;
+                       this.referenceOptions = referenceOptions;
                }
 
-               public CodeTypeReference( Type type, CodeTypeReferenceOptions codeTypeReferenceOption ) :
+               public CodeTypeReference( Type type, CodeTypeReferenceOptions referenceOptions ) :
                        this (type)
                {
-                       this.codeTypeReferenceOption = codeTypeReferenceOption;
+                       this.referenceOptions = referenceOptions;
                }
 
                public CodeTypeReference( string typeName, params CodeTypeReference[] typeArguments ) :
                        this (typeName)
                {
                        TypeArguments.AddRange (typeArguments);
+                       if (this.baseType.IndexOf ('`') < 0)
+                               this.baseType += "`" + TypeArguments.Count;
                }
 #endif
 
@@ -132,24 +155,28 @@ namespace System.CodeDom
                public CodeTypeReference ArrayElementType
                {
                        get {
-                               return arrayType;
+                               return arrayElementType;
                        }
                        set {
-                               arrayType = value;
+                               arrayElementType = value;
                        }
                }
                
                public int ArrayRank {
                        get {
-                               return rank;
+                               return arrayRank;
                        }
                        set {
-                               rank = value;
+                               arrayRank = value;
                        }
                }
 
                public string BaseType {
                        get {
+                               if (arrayElementType != null && arrayRank > 0) {
+                                       return arrayElementType.BaseType;
+                               }
+
                                if (baseType == null)
                                        return String.Empty;
 
@@ -160,14 +187,129 @@ namespace System.CodeDom
                        }
                }
 
+               internal bool IsInterface {
+                       get { return isInterface; }
+               }
+
+               private void Parse (string baseType)
+               {
+                       if (baseType == null || baseType.Length == 0) {
+                               this.baseType = typeof (void).FullName;
+                               return;
+                       }
+
+#if NET_2_0
+                       int array_start = baseType.IndexOf ('[');
+                       if (array_start == -1) {
+                               this.baseType = baseType;
+                               return;
+                       }
+
+                       int array_end = baseType.LastIndexOf (']');
+                       if (array_end < array_start) {
+                               this.baseType = baseType;
+                               return;
+                       }
+
+                       int lastAngle = baseType.LastIndexOf ('>');
+                       if (lastAngle != -1 && lastAngle > array_end) {
+                               this.baseType = baseType;
+                               return;
+                       }
+                       
+                       string[] args = baseType.Substring (array_start + 1, array_end - array_start - 1).Split (',');
+
+                       if ((array_end - array_start) != args.Length) {
+                               this.baseType = baseType.Substring (0, array_start);
+                               int escapeCount = 0;
+                               int scanPos = array_start;
+                               StringBuilder tb = new StringBuilder();
+                               while (scanPos < baseType.Length) {
+                                       char currentChar = baseType[scanPos];
+                                       
+                                       switch (currentChar) {
+                                               case '[':
+                                                       if (escapeCount > 1 && tb.Length > 0) {
+                                                               tb.Append (currentChar);
+                                                       }
+                                                       escapeCount++;
+                                                       break;
+                                               case ']':
+                                                       escapeCount--;
+                                                       if (escapeCount > 1 && tb.Length > 0) {
+                                                               tb.Append (currentChar);
+                                                       }
+
+                                                       if (tb.Length != 0 && (escapeCount % 2) == 0) {
+                                                               TypeArguments.Add (tb.ToString ());
+                                                               tb.Length = 0;
+                                                       }
+                                                       break;
+                                               case ',':
+                                                       if (escapeCount > 1) {
+                                                               // skip anything after the type name until we 
+                                                               // reach the next separator
+                                                               while (scanPos + 1 < baseType.Length) {
+                                                                       if (baseType[scanPos + 1] == ']') {
+                                                                               break;
+                                                                       }
+                                                                       scanPos++;
+                                                               }
+                                                       } else if (tb.Length > 0) {
+                                                               CodeTypeReference typeArg = new CodeTypeReference (tb.ToString ());
+                                                               TypeArguments.Add (typeArg);
+                                                               tb.Length = 0;
+                                                       }
+                                                       break;
+                                               default:
+                                                       tb.Append (currentChar);
+                                                       break;
+                                       }
+                                       scanPos++;
+                               }
+                       } else {
+                               arrayElementType = new CodeTypeReference (baseType.Substring (0, array_start));
+                               arrayRank = args.Length;
+                       }
+#else
+                       int array_start = baseType.LastIndexOf ('[');
+                       if (array_start == -1) {
+                               this.baseType = baseType;
+                               return;
+                       }
+
+                       int array_end = baseType.LastIndexOf (']');
+                       if (array_end < array_start) {
+                               this.baseType = baseType;
+                               return;
+                       }
+
+                       string[] args = baseType.Substring (array_start + 1, array_end - array_start - 1).Split (',');
+
+                       bool isArray = true;
+                       foreach (string arg in args) {
+                               if (arg.Length != 0) {
+                                       isArray = false;
+                                       break;
+                               }
+                       }
+                       if (isArray) {
+                               arrayElementType = new CodeTypeReference (baseType.Substring (0, array_start));
+                               arrayRank = args.Length;
+                       } else {
+                               this.baseType = baseType;
+                       }
+#endif
+               }
+
 #if NET_2_0
                [ComVisible (false)]
                public CodeTypeReferenceOptions Options {
                        get {
-                               return codeTypeReferenceOption;
+                               return referenceOptions;
                        }
                        set {
-                               codeTypeReferenceOption = value;
+                               referenceOptions = value;
                        }
                }
 
@@ -180,5 +322,6 @@ namespace System.CodeDom
                        }
                }
 #endif
+
        }
 }