/main/contrib/NRefactory/Project/Src/Ast/TypeReference.cs
C# | 445 lines | 340 code | 49 blank | 56 comment | 57 complexity | 55d0633fddb7621d20454a405a962aaa MD5 | raw file
1// <file>
2// <copyright see="prj:///doc/copyright.txt"/>
3// <license see="prj:///doc/license.txt"/>
4// <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
5// <version>$Revision: 4482 $</version>
6// </file>
7
8using System;
9using System.Collections.Generic;
10using System.Diagnostics;
11using System.Globalization;
12using System.Runtime.InteropServices;
13using System.Text;
14
15namespace ICSharpCode.OldNRefactory.Ast
16{
17 public class TypeReference : AbstractNode, INullable, ICloneable
18 {
19 public static readonly TypeReference StructConstraint = new TypeReference("constraint: struct");
20 public static readonly TypeReference ClassConstraint = new TypeReference("constraint: class");
21 public static readonly TypeReference NewConstraint = new TypeReference("constraint: new");
22
23 string type = "";
24 int pointerNestingLevel;
25 int[] rankSpecifier;
26 List<TypeReference> genericTypes = new List<TypeReference>();
27
28 #region Static primitive type list
29 static Dictionary<string, string> types = new Dictionary<string, string>();
30 static Dictionary<string, string> vbtypes = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
31 static Dictionary<string, string> typesReverse = new Dictionary<string, string>();
32 static Dictionary<string, string> vbtypesReverse = new Dictionary<string, string>();
33
34 static TypeReference()
35 {
36 // C# types
37 types.Add("bool", "System.Boolean");
38 types.Add("byte", "System.Byte");
39 types.Add("char", "System.Char");
40 types.Add("decimal", "System.Decimal");
41 types.Add("double", "System.Double");
42 types.Add("float", "System.Single");
43 types.Add("int", "System.Int32");
44 types.Add("long", "System.Int64");
45 types.Add("object", "System.Object");
46 types.Add("sbyte", "System.SByte");
47 types.Add("short", "System.Int16");
48 types.Add("string", "System.String");
49 types.Add("uint", "System.UInt32");
50 types.Add("ulong", "System.UInt64");
51 types.Add("ushort", "System.UInt16");
52 types.Add("void", "System.Void");
53
54 // VB.NET types
55 vbtypes.Add("Boolean", "System.Boolean");
56 vbtypes.Add("Byte", "System.Byte");
57 vbtypes.Add("SByte", "System.SByte");
58 vbtypes.Add("Date", "System.DateTime");
59 vbtypes.Add("Char", "System.Char");
60 vbtypes.Add("Decimal", "System.Decimal");
61 vbtypes.Add("Double", "System.Double");
62 vbtypes.Add("Single", "System.Single");
63 vbtypes.Add("Integer", "System.Int32");
64 vbtypes.Add("Long", "System.Int64");
65 vbtypes.Add("UInteger","System.UInt32");
66 vbtypes.Add("ULong", "System.UInt64");
67 vbtypes.Add("Object", "System.Object");
68 vbtypes.Add("Short", "System.Int16");
69 vbtypes.Add("UShort", "System.UInt16");
70 vbtypes.Add("String", "System.String");
71
72 foreach (KeyValuePair<string, string> pair in types) {
73 typesReverse.Add(pair.Value, pair.Key);
74 }
75 foreach (KeyValuePair<string, string> pair in vbtypes) {
76 vbtypesReverse.Add(pair.Value, pair.Key);
77 }
78 }
79
80 /// <summary>
81 /// Gets a shortname=>full name dictionary of C# types.
82 /// </summary>
83 public static IDictionary<string, string> PrimitiveTypesCSharp {
84 get { return types; }
85 }
86
87 /// <summary>
88 /// Gets a shortname=>full name dictionary of VB types.
89 /// </summary>
90 public static IDictionary<string, string> PrimitiveTypesVB {
91 get { return vbtypes; }
92 }
93
94 /// <summary>
95 /// Gets a full name=>shortname dictionary of C# types.
96 /// </summary>
97 public static IDictionary<string, string> PrimitiveTypesCSharpReverse {
98 get { return typesReverse; }
99 }
100
101 /// <summary>
102 /// Gets a full name=>shortname dictionary of VB types.
103 /// </summary>
104 public static IDictionary<string, string> PrimitiveTypesVBReverse {
105 get { return vbtypesReverse; }
106 }
107
108
109 static string GetSystemType(string type)
110 {
111 if (types == null) return type;
112
113 string systemType;
114 if (types.TryGetValue(type, out systemType)) {
115 return systemType;
116 }
117 if (vbtypes.TryGetValue(type, out systemType)) {
118 return systemType;
119 }
120 return type;
121 }
122 #endregion
123
124 object ICloneable.Clone()
125 {
126 return this.Clone();
127 }
128
129 public virtual TypeReference Clone()
130 {
131 TypeReference c = new TypeReference(type);
132 CopyFields(this, c);
133 return c;
134 }
135
136 /// <summary>
137 /// Copies the pointerNestingLevel, RankSpecifier, GenericTypes and IsGlobal flag
138 /// from <paramref name="from"/> to <paramref name="to"/>.
139 /// </summary>
140 /// <remarks>
141 /// If <paramref name="to"/> already contains generics, the new generics are appended to the list.
142 /// </remarks>
143 protected static void CopyFields(TypeReference from, TypeReference to)
144 {
145 to.pointerNestingLevel = from.pointerNestingLevel;
146 if (from.rankSpecifier != null) {
147 to.rankSpecifier = (int[])from.rankSpecifier.Clone();
148 }
149 foreach (TypeReference r in from.genericTypes) {
150 to.genericTypes.Add(r.Clone());
151 }
152 to.IsGlobal = from.IsGlobal;
153 to.IsKeyword = from.IsKeyword;
154 }
155
156 public string Type {
157 get {
158 return type;
159 }
160 set {
161 Debug.Assert(value != null);
162 type = value ?? "?";
163 }
164 }
165
166 /// <summary>
167 /// Removes the last identifier from the type.
168 /// e.g. "System.String.Length" becomes "System.String" or
169 /// "System.Collections.IEnumerable(of string).Current" becomes "System.Collections.IEnumerable(of string)"
170 /// This is used for explicit interface implementation in VB.
171 /// </summary>
172 public static string StripLastIdentifierFromType(ref TypeReference tr)
173 {
174 if (tr is InnerClassTypeReference && ((InnerClassTypeReference)tr).Type.IndexOf('.') < 0) {
175 string ident = ((InnerClassTypeReference)tr).Type;
176 tr = ((InnerClassTypeReference)tr).BaseType;
177 return ident;
178 } else {
179 int pos = tr.Type.LastIndexOf('.');
180 if (pos < 0)
181 return tr.Type;
182 string ident = tr.Type.Substring(pos + 1);
183 tr.Type = tr.Type.Substring(0, pos);
184 return ident;
185 }
186 }
187
188 [Obsolete("Use 'Type' instead - it now contains the SystemType for primitive types.")]
189 public string SystemType {
190 get {
191 return this.Type;
192 }
193 }
194
195 public int PointerNestingLevel {
196 get {
197 return pointerNestingLevel;
198 }
199 set {
200 Debug.Assert(this.IsNull == false);
201 pointerNestingLevel = value;
202 }
203 }
204
205 /// <summary>
206 /// The rank of the array type.
207 /// For "object[]", this is { 0 }; for "object[,]", it is {1}.
208 /// For "object[,][,,][]", it is {1, 2, 0}.
209 /// For non-array types, this property is null or {}.
210 /// </summary>
211 public int[] RankSpecifier {
212 get {
213 return rankSpecifier;
214 }
215 set {
216 Debug.Assert(this.IsNull == false);
217 rankSpecifier = value;
218 }
219 }
220
221 public List<TypeReference> GenericTypes {
222 get {
223 return genericTypes;
224 }
225 }
226
227 public bool IsArrayType {
228 get {
229 return rankSpecifier != null && rankSpecifier.Length > 0;
230 }
231 }
232
233 public static TypeReference CheckNull(TypeReference typeReference)
234 {
235 return typeReference ?? NullTypeReference.Instance;
236 }
237
238 public static TypeReference Null {
239 get {
240 return NullTypeReference.Instance;
241 }
242 }
243
244 public virtual bool IsNull {
245 get {
246 return false;
247 }
248 }
249
250 /// <summary>
251 /// Gets/Sets if the type reference had a "global::" prefix.
252 /// </summary>
253 public bool IsGlobal {
254 get; set;
255 }
256
257 /// <summary>
258 /// Gets/Sets if the type reference was using a language keyword.
259 /// </summary>
260 public bool IsKeyword {
261 get; set;
262 }
263
264 public TypeReference(string type)
265 {
266 this.Type = type;
267 }
268
269 [Obsolete("Type and SystemType are no longer distinguished - use the (string type, bool isKeyword) constructor instead!")]
270 public TypeReference(string type, string systemType)
271 {
272 this.Type = systemType;
273 this.IsKeyword = type != systemType;
274 }
275
276 public TypeReference(string type, bool isKeyword)
277 {
278 this.Type = type;
279 this.IsKeyword = isKeyword;
280 }
281
282 public TypeReference(string type, List<TypeReference> genericTypes) : this(type)
283 {
284 if (genericTypes != null) {
285 this.genericTypes = genericTypes;
286 }
287 }
288
289 public TypeReference(string type, int[] rankSpecifier) : this(type, 0, rankSpecifier)
290 {
291 }
292
293 public TypeReference(string type, int pointerNestingLevel, int[] rankSpecifier) : this(type, pointerNestingLevel, rankSpecifier, null)
294 {
295 }
296
297 public TypeReference(string type, int pointerNestingLevel, int[] rankSpecifier, List<TypeReference> genericTypes)
298 {
299 Debug.Assert(type != null);
300 this.type = type;
301 this.pointerNestingLevel = pointerNestingLevel;
302 this.rankSpecifier = rankSpecifier;
303 if (genericTypes != null) {
304 this.genericTypes = genericTypes;
305 }
306 }
307
308 protected TypeReference()
309 {}
310
311 public override object AcceptVisitor(IAstVisitor visitor, object data)
312 {
313 return visitor.VisitTypeReference(this, data);
314 }
315
316 public override string ToString()
317 {
318 StringBuilder b = new StringBuilder(type);
319 if (genericTypes != null && genericTypes.Count > 0) {
320 b.Append('<');
321 for (int i = 0; i < genericTypes.Count; i++) {
322 if (i > 0) b.Append(',');
323 b.Append(genericTypes[i].ToString());
324 }
325 b.Append('>');
326 }
327 if (pointerNestingLevel > 0) {
328 b.Append('*', pointerNestingLevel);
329 }
330 if (IsArrayType) {
331 foreach (int rank in rankSpecifier) {
332 b.Append('[');
333 if (rank < 0)
334 b.Append('`', -rank);
335 else
336 b.Append(',', rank);
337 b.Append(']');
338 }
339 }
340 return b.ToString();
341 }
342
343 public static bool AreEqualReferences(TypeReference a, TypeReference b)
344 {
345 if (a == b) return true;
346 if (a == null || b == null) return false;
347 if (a is InnerClassTypeReference) a = ((InnerClassTypeReference)a).CombineToNormalTypeReference();
348 if (b is InnerClassTypeReference) b = ((InnerClassTypeReference)b).CombineToNormalTypeReference();
349 if (a.type != b.type) return false;
350 if (a.IsKeyword != b.IsKeyword) return false;
351 if (a.IsGlobal != b.IsGlobal) return false;
352 if (a.pointerNestingLevel != b.pointerNestingLevel) return false;
353 if (a.IsArrayType != b.IsArrayType) return false;
354 if (a.IsArrayType) {
355 if (a.rankSpecifier.Length != b.rankSpecifier.Length) return false;
356 for (int i = 0; i < a.rankSpecifier.Length; i++) {
357 if (a.rankSpecifier[i] != b.rankSpecifier[i]) return false;
358 }
359 }
360 if (a.genericTypes.Count != b.genericTypes.Count) return false;
361 for (int i = 0; i < a.genericTypes.Count; i++) {
362 if (!AreEqualReferences(a.genericTypes[i], b.genericTypes[i]))
363 return false;
364 }
365 return true;
366 }
367 }
368
369 internal sealed class NullTypeReference : TypeReference
370 {
371 public static readonly NullTypeReference Instance = new NullTypeReference();
372 public override bool IsNull {
373 get {
374 return true;
375 }
376 }
377 public override TypeReference Clone()
378 {
379 return this;
380 }
381 public override object AcceptVisitor(IAstVisitor visitor, object data)
382 {
383 return null;
384 }
385
386 public override string ToString()
387 {
388 return String.Format("[NullTypeReference]");
389 }
390 }
391
392 /// <summary>
393 /// We need this special type reference for cases like
394 /// OuterClass(Of T1).InnerClass(Of T2) (in expression or type context)
395 /// or Dictionary(Of String, NamespaceStruct).KeyCollection (in type context, otherwise it's a
396 /// MemberReferenceExpression)
397 /// </summary>
398 public class InnerClassTypeReference: TypeReference
399 {
400 TypeReference baseType;
401
402 public TypeReference BaseType {
403 get { return baseType; }
404 set { baseType = value; }
405 }
406
407 public override TypeReference Clone()
408 {
409 InnerClassTypeReference c = new InnerClassTypeReference(baseType.Clone(), Type, new List<TypeReference>());
410 CopyFields(this, c);
411 return c;
412 }
413
414 public InnerClassTypeReference(TypeReference outerClass, string innerType, List<TypeReference> innerGenericTypes)
415 : base(innerType, innerGenericTypes)
416 {
417 this.baseType = outerClass;
418 }
419
420 public override object AcceptVisitor(IAstVisitor visitor, object data)
421 {
422 return visitor.VisitInnerClassTypeReference(this, data);
423 }
424
425 /// <summary>
426 /// Creates a type reference where all type parameters are specified for the innermost class.
427 /// Namespace.OuterClass(of string).InnerClass(of integer).InnerInnerClass
428 /// becomes Namespace.OuterClass.InnerClass.InnerInnerClass(of string, integer)
429 /// </summary>
430 public TypeReference CombineToNormalTypeReference()
431 {
432 TypeReference tr = (baseType is InnerClassTypeReference)
433 ? ((InnerClassTypeReference)baseType).CombineToNormalTypeReference()
434 : baseType.Clone();
435 CopyFields(this, tr);
436 tr.Type += "." + Type;
437 return tr;
438 }
439
440 public override string ToString()
441 {
442 return "[InnerClassTypeReference: (" + baseType.ToString() + ")." + base.ToString() + "]";
443 }
444 }
445}