* BuildEngine.cs (BuildProjectFile): Use AddProperty method to specify
[mono.git] / mcs / class / System / System.CodeDom / CodeTypeReference.cs
1 //
2 // System.CodeDom CodeTypeReferenceExpression Class implementation
3 //
4 // Author:
5 //   Daniel Stodden (stodden@in.tum.de)
6 //   Marek Safar (marek.safar@seznam.cz)
7 //
8 // (C) 2001 Ximian, Inc.
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.Runtime.InteropServices;
33 using System.Text;
34
35 namespace System.CodeDom
36 {
37         [Serializable]
38         [ClassInterface(ClassInterfaceType.AutoDispatch)]
39         [ComVisible(true)]
40         public class CodeTypeReference : CodeObject
41         {
42                 private string baseType;
43                 private CodeTypeReference arrayType;
44                 private int rank;
45                 private bool isInterface;
46
47 #if NET_2_0
48                 CodeTypeReferenceCollection typeArguments;
49                 CodeTypeReferenceOptions codeTypeReferenceOption;
50 #endif
51
52                 //
53                 // Constructors
54                 //
55
56 #if NET_2_0
57                 public CodeTypeReference ()
58                 {
59                 }
60 #endif
61
62 #if NET_2_0
63                 [MonoTODO("We should parse basetype from right to left in 2.0 profile.")]
64 #endif
65                 public CodeTypeReference (string baseType)
66                 {
67                         Parse (baseType);
68                 }
69
70 #if NET_2_0
71                 [MonoTODO("We should parse basetype from right to left in 2.0 profile.")]
72 #endif
73                 public CodeTypeReference (Type baseType)
74                 {
75 #if NET_2_0
76                         if (baseType == null) {
77                                 throw new ArgumentNullException ("baseType");
78                         }
79
80                         if (baseType.IsGenericParameter) {
81                                 this.baseType = baseType.Name;
82                                 this.codeTypeReferenceOption = CodeTypeReferenceOptions.GenericTypeParameter;
83                         }
84                         else if (baseType.IsGenericTypeDefinition)
85                                 this.baseType = baseType.FullName;
86                         else if (baseType.IsGenericType) {
87                                 this.baseType = baseType.GetGenericTypeDefinition ().FullName;
88                                 foreach (Type arg in baseType.GetGenericArguments ()) {
89                                         if (arg.IsGenericParameter)
90                                                 TypeArguments.Add (new CodeTypeReference (new CodeTypeParameter (arg.Name)));
91                                         else
92                                                 TypeArguments.Add (new CodeTypeReference (arg));
93                                 }
94                         }
95                         else
96 #endif
97                         if (baseType.IsArray) {
98                                 this.rank = baseType.GetArrayRank ();
99                                 this.arrayType = new CodeTypeReference (baseType.GetElementType ());
100                                 this.baseType = arrayType.BaseType;
101                         } else {
102                                 Parse (baseType.FullName);
103                         }
104                         this.isInterface = baseType.IsInterface;
105                 }
106
107                 public CodeTypeReference( CodeTypeReference arrayType, int rank )
108                 {
109                         this.baseType = null;
110                         this.rank = rank;
111                         this.arrayType = arrayType;
112                 }
113
114 #if NET_2_0
115                 [MonoTODO("We should parse basetype from right to left in 2.0 profile.")]
116 #endif
117                 public CodeTypeReference( string baseType, int rank )
118                         : this (new CodeTypeReference (baseType), rank)
119                 {
120                 }
121
122 #if NET_2_0
123                 public CodeTypeReference( CodeTypeParameter typeParameter ) :
124                         this (typeParameter.Name)
125                 {
126                         this.codeTypeReferenceOption = CodeTypeReferenceOptions.GenericTypeParameter;
127                 }
128
129                 public CodeTypeReference( string typeName, CodeTypeReferenceOptions codeTypeReferenceOption ) :
130                         this (typeName)
131                 {
132                         this.codeTypeReferenceOption = codeTypeReferenceOption;
133                 }
134
135                 public CodeTypeReference( Type type, CodeTypeReferenceOptions codeTypeReferenceOption ) :
136                         this (type)
137                 {
138                         this.codeTypeReferenceOption = codeTypeReferenceOption;
139                 }
140
141                 public CodeTypeReference( string typeName, params CodeTypeReference[] typeArguments ) :
142                         this (typeName)
143                 {
144                         TypeArguments.AddRange (typeArguments);
145                         if (this.baseType.IndexOf ('`') < 0)
146                                 this.baseType += "`" + TypeArguments.Count;
147                 }
148 #endif
149
150                 //
151                 // Properties
152                 //
153
154                 public CodeTypeReference ArrayElementType
155                 {
156                         get {
157                                 return arrayType;
158                         }
159                         set {
160                                 arrayType = value;
161                         }
162                 }
163                 
164                 public int ArrayRank {
165                         get {
166                                 return rank;
167                         }
168                         set {
169                                 rank = value;
170                         }
171                 }
172
173                 public string BaseType {
174                         get {
175                                 if (arrayType != null && rank > 0) {
176                                         return arrayType.BaseType;
177                                 }
178
179                                 if (baseType == null)
180                                         return String.Empty;
181
182                                 return baseType;
183                         }
184                         set {
185                                 baseType = value;
186                         }
187                 }
188
189                 internal bool IsInterface {
190                         get { return isInterface; }
191                 }
192
193                 private void Parse (string baseType)
194                 {
195                         if (baseType == null || baseType.Length == 0) {
196                                 this.baseType = typeof (void).FullName;
197                                 return;
198                         }
199
200 #if NET_2_0
201                         int array_start = baseType.IndexOf ('[');
202                         if (array_start == -1) {
203                                 this.baseType = baseType;
204                                 return;
205                         }
206
207                         int array_end = baseType.LastIndexOf (']');
208                         if (array_end < array_start) {
209                                 this.baseType = baseType;
210                                 return;
211                         }
212
213                         string[] args = baseType.Substring (array_start + 1, array_end - array_start - 1).Split (',');
214
215                         if ((array_end - array_start) != args.Length) {
216                                 this.baseType = baseType.Substring (0, array_start);
217                                 int escapeCount = 0;
218                                 int scanPos = array_start;
219                                 StringBuilder tb = new StringBuilder();
220                                 while (scanPos < baseType.Length) {
221                                         char currentChar = baseType[scanPos];
222                                         
223                                         switch (currentChar) {
224                                                 case '[':
225                                                         if (escapeCount > 1 && tb.Length > 0) {
226                                                                 tb.Append (currentChar);
227                                                         }
228                                                         escapeCount++;
229                                                         break;
230                                                 case ']':
231                                                         escapeCount--;
232                                                         if (escapeCount > 1 && tb.Length > 0) {
233                                                                 tb.Append (currentChar);
234                                                         }
235
236                                                         if (tb.Length != 0 && (escapeCount % 2) == 0) {
237                                                                 TypeArguments.Add (tb.ToString ());
238                                                                 tb.Length = 0;
239                                                         }
240                                                         break;
241                                                 case ',':
242                                                         if (escapeCount > 1) {
243                                                                 // skip anything after the type name until we 
244                                                                 // reach the next separator
245                                                                 while (scanPos + 1 < baseType.Length) {
246                                                                         if (baseType[scanPos + 1] == ']') {
247                                                                                 break;
248                                                                         }
249                                                                         scanPos++;
250                                                                 }
251                                                         } else if (tb.Length > 0) {
252                                                                 CodeTypeReference typeArg = new CodeTypeReference (tb.ToString ());
253                                                                 TypeArguments.Add (typeArg);
254                                                                 tb.Length = 0;
255                                                         }
256                                                         break;
257                                                 default:
258                                                         tb.Append (currentChar);
259                                                         break;
260                                         }
261                                         scanPos++;
262                                 }
263                         } else {
264                                 arrayType = new CodeTypeReference (baseType.Substring (0, array_start));
265                                 rank = args.Length;
266                         }
267 #else
268                         int array_start = baseType.LastIndexOf ('[');
269                         if (array_start == -1) {
270                                 this.baseType = baseType;
271                                 return;
272                         }
273
274                         int array_end = baseType.LastIndexOf (']');
275                         if (array_end < array_start) {
276                                 this.baseType = baseType;
277                                 return;
278                         }
279
280                         string[] args = baseType.Substring (array_start + 1, array_end - array_start - 1).Split (',');
281
282                         bool isArray = true;
283                         foreach (string arg in args) {
284                                 if (arg.Length != 0) {
285                                         isArray = false;
286                                         break;
287                                 }
288                         }
289                         if (isArray) {
290                                 arrayType = new CodeTypeReference (baseType.Substring (0, array_start));
291                                 rank = args.Length;
292                         } else {
293                                 this.baseType = baseType;
294                         }
295 #endif
296                 }
297
298 #if NET_2_0
299                 [ComVisible (false)]
300                 public CodeTypeReferenceOptions Options {
301                         get {
302                                 return codeTypeReferenceOption;
303                         }
304                         set {
305                                 codeTypeReferenceOption = value;
306                         }
307                 }
308
309                 [ComVisible (false)]
310                 public CodeTypeReferenceCollection TypeArguments {
311                         get {
312                                 if (typeArguments == null)
313                                         typeArguments = new CodeTypeReferenceCollection ();
314                                 return typeArguments;
315                         }
316                 }
317 #endif
318
319         }
320 }