1 //
2 // TypeReference.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@gmail.com)
6 //
7 // Copyright (c) 2008 - 2011 Jb Evain
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 
29 using System;
30 
31 using Mono.Cecil.Metadata;
32 using Mono.Collections.Generic;
33 
34 namespace Mono.Cecil {
35 
36 	public enum MetadataType : byte {
37 		Void = ElementType.Void,
38 		Boolean = ElementType.Boolean,
39 		Char = ElementType.Char,
40 		SByte = ElementType.I1,
41 		Byte = ElementType.U1,
42 		Int16 = ElementType.I2,
43 		UInt16 = ElementType.U2,
44 		Int32 = ElementType.I4,
45 		UInt32 = ElementType.U4,
46 		Int64 = ElementType.I8,
47 		UInt64 = ElementType.U8,
48 		Single = ElementType.R4,
49 		Double = ElementType.R8,
50 		String = ElementType.String,
51 		Pointer = ElementType.Ptr,
52 		ByReference = ElementType.ByRef,
53 		ValueType = ElementType.ValueType,
54 		Class = ElementType.Class,
55 		Var = ElementType.Var,
56 		Array = ElementType.Array,
57 		GenericInstance = ElementType.GenericInst,
58 		TypedByReference = ElementType.TypedByRef,
59 		IntPtr = ElementType.I,
60 		UIntPtr = ElementType.U,
61 		FunctionPointer = ElementType.FnPtr,
62 		Object = ElementType.Object,
63 		MVar = ElementType.MVar,
64 		RequiredModifier = ElementType.CModReqD,
65 		OptionalModifier = ElementType.CModOpt,
66 		Sentinel = ElementType.Sentinel,
67 		Pinned = ElementType.Pinned,
68 	}
69 
70 	public class TypeReference : MemberReference, IGenericParameterProvider, IGenericContext {
71 
72 		string @namespace;
73 		bool value_type;
74 		internal IMetadataScope scope;
75 		internal ModuleDefinition module;
76 
77 		internal ElementType etype = ElementType.None;
78 
79 		string fullname;
80 
81 		protected Collection<GenericParameter> generic_parameters;
82 
83 		public override string Name {
84 			get { return base.Name; }
85 			set {
86 				base.Name = value;
87 				fullname = null;
88 			}
89 		}
90 
91 		public virtual string Namespace {
92 			get { return @namespace; }
93 			set {
94 				@namespace = value;
95 				fullname = null;
96 			}
97 		}
98 
99 		public virtual bool IsValueType {
100 			get { return value_type; }
101 			set { value_type = value; }
102 		}
103 
104 		public override ModuleDefinition Module {
105 			get {
106 				if (module != null)
107 					return module;
108 
109 				var declaring_type = this.DeclaringType;
110 				if (declaring_type != null)
111 					return declaring_type.Module;
112 
113 				return null;
114 			}
115 		}
116 
117 		IGenericParameterProvider IGenericContext.Type {
118 			get { return this; }
119 		}
120 
121 		IGenericParameterProvider IGenericContext.Method {
122 			get { return null; }
123 		}
124 
125 		GenericParameterType IGenericParameterProvider.GenericParameterType {
126 			get { return GenericParameterType.Type; }
127 		}
128 
129 		public virtual bool HasGenericParameters {
130 			get { return !generic_parameters.IsNullOrEmpty (); }
131 		}
132 
133 		public virtual Collection<GenericParameter> GenericParameters {
134 			get {
135 				if (generic_parameters != null)
136 					return generic_parameters;
137 
138 				return generic_parameters = new GenericParameterCollection (this);
139 			}
140 		}
141 
142 		public virtual IMetadataScope Scope {
143 			get {
144 				var declaring_type = this.DeclaringType;
145 				if (declaring_type != null)
146 					return declaring_type.Scope;
147 
148 				return scope;
149 			}
150 			set {
151 				var declaring_type = this.DeclaringType;
152 				if (declaring_type != null) {
153 					declaring_type.Scope = value;
154 					return;
155 				}
156 
157 				scope = value;
158 			}
159 		}
160 
161 		public bool IsNested {
162 			get { return this.DeclaringType != null; }
163 		}
164 
165 		public override TypeReference DeclaringType {
166 			get { return base.DeclaringType; }
167 			set {
168 				base.DeclaringType = value;
169 				fullname = null;
170 			}
171 		}
172 
173 		public override string FullName {
174 			get {
175 				if (fullname != null)
176 					return fullname;
177 
178 				if (IsNested)
179 					return fullname = DeclaringType.FullName + "/" + Name;
180 
181 				if (string.IsNullOrEmpty (@namespace))
182 					return fullname = Name;
183 
184 				return fullname = @namespace + "." + Name;
185 			}
186 		}
187 
188 		public virtual bool IsByReference {
189 			get { return false; }
190 		}
191 
192 		public virtual bool IsPointer {
193 			get { return false; }
194 		}
195 
196 		public virtual bool IsSentinel {
197 			get { return false; }
198 		}
199 
200 		public virtual bool IsArray {
201 			get { return false; }
202 		}
203 
204 		public virtual bool IsGenericParameter {
205 			get { return false; }
206 		}
207 
208 		public virtual bool IsGenericInstance {
209 			get { return false; }
210 		}
211 
212 		public virtual bool IsRequiredModifier {
213 			get { return false; }
214 		}
215 
216 		public virtual bool IsOptionalModifier {
217 			get { return false; }
218 		}
219 
220 		public virtual bool IsPinned {
221 			get { return false; }
222 		}
223 
224 		public virtual bool IsFunctionPointer {
225 			get { return false; }
226 		}
227 
228 		public virtual bool IsPrimitive {
229 			get { return etype.IsPrimitive (); }
230 		}
231 
232 		public virtual MetadataType MetadataType {
233 			get {
234 				switch (etype) {
235 				case ElementType.None:
236 					return IsValueType ? MetadataType.ValueType : MetadataType.Class;
237 				default:
238 					return (MetadataType) etype;
239 				}
240 			}
241 		}
242 
TypeReference(string @namespace, string name)243 		protected TypeReference (string @namespace, string name)
244 			: base (name)
245 		{
246 			this.@namespace = @namespace ?? string.Empty;
247 			this.token = new MetadataToken (TokenType.TypeRef, 0);
248 		}
249 
TypeReference(string @namespace, string name, ModuleDefinition module, IMetadataScope scope)250 		public TypeReference (string @namespace, string name, ModuleDefinition module, IMetadataScope scope)
251 			: this (@namespace, name)
252 		{
253 			this.module = module;
254 			this.scope = scope;
255 		}
256 
TypeReference(string @namespace, string name, ModuleDefinition module, IMetadataScope scope, bool valueType)257 		public TypeReference (string @namespace, string name, ModuleDefinition module, IMetadataScope scope, bool valueType) :
258 			this (@namespace, name, module, scope)
259 		{
260 			value_type = valueType;
261 		}
262 
GetElementType()263 		public virtual TypeReference GetElementType ()
264 		{
265 			return this;
266 		}
267 
Resolve()268 		public virtual TypeDefinition Resolve ()
269 		{
270 			var module = this.Module;
271 			if (module == null)
272 				throw new NotSupportedException ();
273 
274 			return module.Resolve (this);
275 		}
276 	}
277 
278 	static partial class Mixin {
279 
IsPrimitive(this ElementType self)280 		public static bool IsPrimitive (this ElementType self)
281 		{
282 			switch (self) {
283 			case ElementType.Boolean:
284 			case ElementType.Char:
285 			case ElementType.I:
286 			case ElementType.U:
287 			case ElementType.I1:
288 			case ElementType.U1:
289 			case ElementType.I2:
290 			case ElementType.U2:
291 			case ElementType.I4:
292 			case ElementType.U4:
293 			case ElementType.I8:
294 			case ElementType.U8:
295 			case ElementType.R4:
296 			case ElementType.R8:
297 				return true;
298 			default:
299 				return false;
300 			}
301 		}
302 
IsTypeOf(this TypeReference self, string @namespace, string name)303 		public static bool IsTypeOf (this TypeReference self, string @namespace, string name)
304 		{
305 			return self.Name == name
306 				&& self.Namespace == @namespace;
307 		}
308 
IsTypeSpecification(this TypeReference type)309 		public static bool IsTypeSpecification (this TypeReference type)
310 		{
311 			switch (type.etype) {
312 			case ElementType.Array:
313 			case ElementType.ByRef:
314 			case ElementType.CModOpt:
315 			case ElementType.CModReqD:
316 			case ElementType.FnPtr:
317 			case ElementType.GenericInst:
318 			case ElementType.MVar:
319 			case ElementType.Pinned:
320 			case ElementType.Ptr:
321 			case ElementType.SzArray:
322 			case ElementType.Sentinel:
323 			case ElementType.Var:
324 				return true;
325 			}
326 
327 			return false;
328 		}
329 
CheckedResolve(this TypeReference self)330 		public static TypeDefinition CheckedResolve (this TypeReference self)
331 		{
332 			var type = self.Resolve ();
333 			if (type == null)
334 				throw new ResolutionException (self);
335 
336 			return type;
337 		}
338 	}
339 }
340