1 //
2 // MetaDataProvider.cs
3 //
4 // Authors:
5 // 	Alexander Chebaturkin (chebaturkin@gmail.com)
6 //
7 // Copyright (C) 2011 Alexander Chebaturkin
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 using System.Collections.Generic;
31 using System.Linq;
32 using Mono.Cecil;
33 using Mono.CodeContracts.Static.AST;
34 using Mono.CodeContracts.Static.AST.Visitors;
35 using Mono.CodeContracts.Static.ContractExtraction;
36 using Mono.CodeContracts.Static.DataStructures;
37 
38 namespace Mono.CodeContracts.Static.Providers {
39 	class MetaDataProvider : IMetaDataProvider {
40 		public static readonly MetaDataProvider Instance = new MetaDataProvider ();
41 
42 		#region IMetaDataProvider Members
AccessMethodBody(Method method, IMethodCodeConsumer<Data, Result> consumer, Data data)43 		public Result AccessMethodBody<Data, Result> (Method method, IMethodCodeConsumer<Data, Result> consumer, Data data)
44 		{
45 			return consumer.Accept (CodeProviderImpl.Instance, CodeProviderImpl.Instance.Entry (method), method, data);
46 		}
47 
IsReferenceType(TypeNode type)48 		public bool IsReferenceType (TypeNode type)
49 		{
50 			return (!type.IsValueType);
51 		}
52 
DeclaringMethod(Parameter parameter)53 		public Method DeclaringMethod (Parameter parameter)
54 		{
55 			return parameter.DeclaringMethod;
56 		}
57 
ParameterIndex(Parameter parameter)58 		public int ParameterIndex (Parameter parameter)
59 		{
60 			return parameter.Index;
61 		}
62 
IsVoidMethod(Method method)63 		public bool IsVoidMethod (Method method)
64 		{
65 			return IsVoid (method.ReturnType);
66 		}
67 
TryLoadAssembly(string filename, out AssemblyNode assembly, out string reasonOfFailure)68 		public bool TryLoadAssembly (string filename, out AssemblyNode assembly, out string reasonOfFailure)
69 		{
70 			assembly = AssemblyNode.ReadAssembly (filename);
71 			if (!TryLoadContractNodes (ref assembly)) {
72 				reasonOfFailure = "Couldn't find CodeContracts assembly in referencing assemblies";
73 				return false;
74 			}
75 			reasonOfFailure = null;
76 			return true;
77 		}
78 
ReturnType(Method method)79 		public TypeNode ReturnType (Method method)
80 		{
81 			return method.ReturnType;
82 		}
83 
Parameters(Method method)84 		public IIndexable<Parameter> Parameters (Method method)
85 		{
86 			return new Indexable<Parameter> (method.Parameters);
87 		}
88 
This(Method method)89 		public Parameter This (Method method)
90 		{
91 			return method.ThisParameter;
92 		}
93 
Name(Method method)94 		public string Name (Method method)
95 		{
96 			return method.Name;
97 		}
98 
Name(Field field)99 		public string Name (Field field)
100 		{
101 			return field.Name;
102 		}
103 
Name(TypeNode type)104 		public string Name (TypeNode type)
105 		{
106 			return type.Name;
107 		}
108 
FieldType(Field field)109 		public TypeNode FieldType (Field field)
110 		{
111 			return field.FieldType;
112 		}
113 
FullName(Method method)114 		public string FullName (Method method)
115 		{
116 			return method.FullName;
117 		}
118 
FullName(TypeNode type)119 		public string FullName (TypeNode type)
120 		{
121 			return type.FullName;
122 		}
123 
DeclaringType(Field field)124 		public TypeNode DeclaringType (Field field)
125 		{
126 			return field.DeclaringType;
127 		}
128 
IsMain(Method method)129 		public bool IsMain (Method method)
130 		{
131 			MethodDefinition entryPoint = method.Definition.Module.EntryPoint;
132 
133 			return entryPoint != null && entryPoint.Equals (method);
134 		}
135 
IsStatic(Method method)136 		public bool IsStatic (Method method)
137 		{
138 			return method.IsStatic;
139 		}
140 
IsStatic(Field field)141 		public bool IsStatic (Field field)
142 		{
143 			return field.IsStatic;
144 		}
145 
IsPrivate(Method method)146 		public bool IsPrivate (Method method)
147 		{
148 			return method.IsPrivate;
149 		}
150 
IsProtected(Method method)151 		public bool IsProtected (Method method)
152 		{
153 			return method.IsProtected;
154 		}
155 
IsPublic(Method method)156 		public bool IsPublic (Method method)
157 		{
158 			return method.IsPublic;
159 		}
160 
IsVirtual(Method method)161 		public bool IsVirtual (Method method)
162 		{
163 			return method.IsVirtual;
164 		}
165 
IsNewSlot(Method method)166 		public bool IsNewSlot (Method method)
167 		{
168 			return method.IsNewSlot;
169 		}
170 
IsOverride(Method method)171 		public bool IsOverride (Method method)
172 		{
173 			return !method.IsNewSlot && method.HasOverrides;
174 		}
175 
IsFinal(Method method)176 		public bool IsFinal (Method method)
177 		{
178 			return method.IsFinal;
179 		}
180 
IsConstructor(Method method)181 		public bool IsConstructor (Method method)
182 		{
183 			return method.IsConstructor;
184 		}
185 
IsAbstract(Method method)186 		public bool IsAbstract (Method method)
187 		{
188 			return method.IsAbstract;
189 		}
190 
IsPropertySetter(Method method, out Property property)191 		public bool IsPropertySetter (Method method, out Property property)
192 		{
193 			//todo: implement this
194 
195 			property = null;
196 			return false;
197 		}
198 
IsPropertyGetter(Method method, out Property property)199 		public bool IsPropertyGetter (Method method, out Property property)
200 		{
201 			//todo: implement this
202 
203 			property = null;
204 			return false;
205 		}
206 
DeclaringType(Method method)207 		public TypeNode DeclaringType (Method method)
208 		{
209 			return method.DeclaringType;
210 		}
211 
HasBody(Method method)212 		public bool HasBody (Method method)
213 		{
214 			return method.HasBody;
215 		}
216 
DerivesFrom(TypeNode sub, TypeNode type)217 		public bool DerivesFrom (TypeNode sub, TypeNode type)
218 		{
219 			return sub.IsAssignableTo (type);
220 		}
221 
Equal(TypeNode type, TypeNode otherType)222 		public bool Equal (TypeNode type, TypeNode otherType)
223 		{
224 			return type == otherType;
225 		}
226 
TryGetImplementingMethod(TypeNode type, Method calledMethod, out Method implementingMethod)227 		public bool TryGetImplementingMethod (TypeNode type, Method calledMethod, out Method implementingMethod)
228 		{
229 			//todo: implement this
230 			implementingMethod = null;
231 			return false;
232 		}
233 
Unspecialized(Method method)234 		public Method Unspecialized (Method method)
235 		{
236 			if (method.HasGenericParameters)
237 				throw new NotImplementedException ();
238 
239 			return method;
240 		}
241 
OverridenAndImplementedMethods(Method method)242 		public IEnumerable<Method> OverridenAndImplementedMethods (Method method)
243 		{
244 			//todo: implement this
245 			yield break;
246 		}
247 
ManagedPointer(TypeNode type)248 		public TypeNode ManagedPointer (TypeNode type)
249 		{
250 			return type.GetReferenceType ();
251 		}
252 
TryGetRootMethod(Method method, out Method rootMethod)253 		public bool TryGetRootMethod (Method method, out Method rootMethod)
254 		{
255 			//todo: implement this
256 			rootMethod = method;
257 			return true;
258 		}
259 
ImplementedMethods(Method method)260 		public IEnumerable<Method> ImplementedMethods (Method method)
261 		{
262 			yield break;
263 		}
264 
IsAutoPropertyMember(Method method)265 		public bool IsAutoPropertyMember (Method method)
266 		{
267 			//todo: implement this
268 			return false;
269 		}
270 
IsFinalizer(Method method)271 		public bool IsFinalizer (Method method)
272 		{
273 			return "Finalize" == method.Name;
274 		}
275 
IsDispose(Method method)276 		public bool IsDispose (Method method)
277 		{
278 			if (method.Name != "Dispose" && method.Name != "System.IDisposable.Dispose")
279 				return false;
280 			if (method.Parameters == null || method.Parameters.Count == 0)
281 				return true;
282 			if (method.Parameters.Count == 1)
283 				return Equal(method.Parameters [0].Type, CoreSystemTypes.Instance.TypeBoolean);
284 
285 			return false;
286 		}
287 		#endregion
288 
289 		#region Implementation of IMetaDataProvider<Local,Parameter,Method,FieldReference,PropertyReference,EventReference,TypeNode,Attribute,AssemblyNode>
290 
291 	        public TypeNode System_Single
292 	        {
293 	                get { return CoreSystemTypes.Instance.TypeSingle; }
294 	        }
295 
296 	        public TypeNode System_Double
297 		{
298 			get { return CoreSystemTypes.Instance.TypeDouble; }
299 		}
300 
301 	        public TypeNode System_Type
302 		{
303 			get { return CoreSystemTypes.Instance.TypeSystemType; }
304 		}
305 
306 		public TypeNode System_Char
307 		{
308 			get { return CoreSystemTypes.Instance.TypeChar; }
309 		}
310 
311 		public TypeNode System_Int32
312 		{
313 			get { return CoreSystemTypes.Instance.TypeInt32; }
314 		}
315 
316 		public TypeNode System_String
317 		{
318 			get { return CoreSystemTypes.Instance.TypeString; }
319 		}
320 
321 		public TypeNode System_Boolean
322 		{
323 			get { return CoreSystemTypes.Instance.TypeBoolean; }
324 		}
325 
326 		public TypeNode System_IntPtr
327 		{
328 			get { return CoreSystemTypes.Instance.TypeIntPtr; }
329 		}
330 
331 		public TypeNode System_UIntPtr
332 		{
333 			get { return CoreSystemTypes.Instance.TypeUIntPtr; }
334 		}
335 
336 		public TypeNode System_Void
337 		{
338 			get { return CoreSystemTypes.Instance.TypeVoid; }
339 		}
340 
341 		public TypeNode System_Array
342 		{
343 			get { return CoreSystemTypes.Instance.TypeArray; }
344 		}
345 
346 		public TypeNode System_Object
347 		{
348 			get { return CoreSystemTypes.Instance.TypeObject; }
349 		}
350 
351 		public TypeNode System_Int8
352 		{
353 			get { return CoreSystemTypes.Instance.TypeSByte; }
354 		}
355 
356 		public TypeNode System_Int64
357 		{
358 			get { return CoreSystemTypes.Instance.TypeInt64; }
359 		}
360 
361 		public TypeNode System_Int16
362 		{
363 			get { return CoreSystemTypes.Instance.TypeInt16; }
364 		}
365 
366 		public TypeNode System_UInt8
367 		{
368 			get { return CoreSystemTypes.Instance.TypeByte; }
369 		}
370 
371 		public TypeNode System_UInt64
372 		{
373 			get { return CoreSystemTypes.Instance.TypeUInt64; }
374 		}
375 
376 		public TypeNode System_UInt32
377 		{
378 			get { return CoreSystemTypes.Instance.TypeUInt32; }
379 		}
380 
381 		public TypeNode System_UInt16
382 		{
383 			get { return CoreSystemTypes.Instance.TypeUInt16; }
384 		}
385 
Methods(AssemblyNode assembly)386 		public IEnumerable<Method> Methods (AssemblyNode assembly)
387 		{
388 			return assembly.Modules.SelectMany (a => a.Types).SelectMany (t => t.Methods);
389 		}
390 
Name(Parameter parameter)391 		public string Name (Parameter parameter)
392 		{
393 			return parameter.Name;
394 		}
395 
ParameterType(Parameter parameter)396 		public TypeNode ParameterType (Parameter parameter)
397 		{
398 			return parameter.Type;
399 		}
400 
LocalType(Local local)401 		public TypeNode LocalType (Local local)
402 		{
403 			return local.Type;
404 		}
405 
IsStruct(TypeNode type)406 		public bool IsStruct (TypeNode type)
407 		{
408 			return type.IsValueType;
409 		}
410 
Unspecialized(Field field)411 		public Field Unspecialized (Field field)
412 		{
413 			return field;
414 		}
415 
IsManagedPointer(TypeNode value)416 		public bool IsManagedPointer (TypeNode value)
417 		{
418 			return value is Reference;
419 		}
420 
IsArray(TypeNode type)421 		public bool IsArray (TypeNode type)
422 		{
423 			return type.IsArray;
424 		}
425 
Interfaces(TypeNode type)426 		public IEnumerable<TypeNode> Interfaces (TypeNode type)
427 		{
428 			return type.Interfaces;
429 		}
430 
TryGetSystemType(string fullName, out TypeNode type)431 		public bool TryGetSystemType (string fullName, out TypeNode type)
432 		{
433 			int len = fullName.LastIndexOf (".");
434 			string ns = "";
435 			string className = fullName;
436 			if (len > 0) {
437 				ns = fullName.Substring (0, len);
438 				className = fullName.Substring (len + 1);
439 			}
440 			type = CoreSystemTypes.Instance.SystemAssembly.GetType (ns, className);
441 			return type != null;
442 		}
443 
IsInterface(TypeNode type)444 		public bool IsInterface (TypeNode type)
445 		{
446 			return type.IsInterface;
447 		}
448 
Properties(TypeNode type)449 		public IEnumerable<Property> Properties (TypeNode type)
450 		{
451 			return type.Properties;
452 		}
453 
IsStatic(Property property)454 		public bool IsStatic (Property property)
455 		{
456 			return property.IsStatic;
457 		}
458 
IsAsVisibleAs(Field value, Method method)459 		public bool IsAsVisibleAs (Field value, Method method)
460 		{
461 			return HelperMethods.IsReferenceAsVisibleAs (value, method);
462 		}
463 
IsAsVisibleAs(Method value, Method method)464 		public bool IsAsVisibleAs (Method value, Method method)
465 		{
466 			return HelperMethods.IsReferenceAsVisibleAs (value, method);
467 		}
468 
IsVisibleFrom(Field field, TypeNode declaringType)469 		public bool IsVisibleFrom (Field field, TypeNode declaringType)
470 		{
471 			return field.IsVisibleFrom (declaringType);
472 		}
473 
IsVisibleFrom(Method value, TypeNode declaringType)474 		public bool IsVisibleFrom (Method value, TypeNode declaringType)
475 		{
476 			return value.IsVisibleFrom (declaringType);
477 		}
478 
Equal(Method thisMethod, Method thatMethod)479 		public bool Equal (Method thisMethod, Method thatMethod)
480 		{
481 			return thisMethod == thatMethod;
482 		}
483 
Locals(Method method)484 		public IIndexable<Local> Locals (Method method)
485 		{
486 			return new Indexable<Local> (method.Locals);
487 		}
488 
ElementType(TypeNode type)489 		public TypeNode ElementType (TypeNode type)
490 		{
491 			var reference = type as Reference;
492 			if (reference != null)
493 				return reference.ElementType;
494 			//todo: array
495 
496 			throw new NotImplementedException ();
497 		}
498 
Unspecialized(TypeNode type)499 		public TypeNode Unspecialized (TypeNode type)
500 		{
501 			return type;
502 		}
503 
IsProtected(Field field)504 		public bool IsProtected (Field field)
505 		{
506 			return field.IsFamily || field.IsFamilyAndAssembly || field.IsFamilyOrAssembly;
507 		}
508 
IsPublic(Field field)509 		public bool IsPublic (Field field)
510 		{
511 			return field.IsPublic;
512 		}
513 
ParameterStackIndex(Parameter parameter)514 		public int ParameterStackIndex (Parameter parameter)
515 		{
516 			Method declaringMethod = parameter.DeclaringMethod;
517 			return declaringMethod.Parameters.Count + (declaringMethod.IsStatic ? 0 : 1) - parameter.Index - 1;
518 		}
519 
HasGetter(Property property, out Method method)520 		public bool HasGetter (Property property, out Method method)
521 		{
522 			if (property.HasGetter) {
523 				method = property.Getter;
524 				return true;
525 			}
526 			method = null;
527 			return false;
528 		}
529 
HasSetter(Property property, out Method method)530 		public bool HasSetter (Property property, out Method method)
531 		{
532 			if (property.HasSetter) {
533 				method = property.Setter;
534 				return true;
535 			}
536 			method = null;
537 			return false;
538 		}
539 
IsReadonly(Field value)540 		public bool IsReadonly (Field value)
541 		{
542 			return value.IsReadonly;
543 		}
544 
HasValueRepresentation(TypeNode type)545 		public bool HasValueRepresentation (TypeNode type)
546 		{
547 			return !IsStruct (type) || IsPrimitive (type) || IsEnum (type);
548 		}
549 
IsVoid(TypeNode type)550 		public bool IsVoid (TypeNode type)
551 		{
552 			return type.Equals (System_Void);
553 		}
554 
IsSpecialized(Method calledMethod, ref IImmutableMap<TypeNode, TypeNode> specialization)555 		public void IsSpecialized (Method calledMethod, ref IImmutableMap<TypeNode, TypeNode> specialization)
556 		{
557 			throw new NotImplementedException ();
558 		}
559 
Fields(TypeNode type)560 		public IEnumerable<Field> Fields (TypeNode type)
561 		{
562 			return type.Fields;
563 		}
564 
IsOut(Parameter p)565 		public bool IsOut (Parameter p)
566 		{
567 			return p.IsOut;
568 		}
569 
IsPrimitive(TypeNode type)570 		public bool IsPrimitive (TypeNode type)
571 		{
572 			return type.IsPrimitive;
573 		}
574 
IsClass(TypeNode type)575 		public bool IsClass (TypeNode type)
576 		{
577 			return type.IsClass;
578 		}
579 
IsVisibleFrom(TypeNode type, TypeNode fromType)580 		public bool IsVisibleFrom (TypeNode type, TypeNode fromType)
581 		{
582 			return type.IsVisibleFrom (fromType);
583 		}
584 
IsCompilerGenerated(Method method)585 		public bool IsCompilerGenerated (Method method)
586 		{
587 			return method.IsCompilerGenerated;
588 		}
589 
IsSpecialized(Method method)590 		public bool IsSpecialized (Method method)
591 		{
592 			return false;
593 		}
594 
IsFormalTypeParameter(TypeNode type)595 		public bool IsFormalTypeParameter (TypeNode type)
596 		{
597 			return false;
598 		}
599 
IsMethodFormalTypeParameter(TypeNode type)600 		public bool IsMethodFormalTypeParameter (TypeNode type)
601 		{
602 			return false;
603 		}
604 
ArrayType(TypeNode type, int rank)605 		public TypeNode ArrayType (TypeNode type, int rank)
606 		{
607 			return type.GetArrayType (rank);
608 		}
609 
IsCompilerGenerated(Field field)610 		public bool IsCompilerGenerated (Field field)
611 		{
612 			return field.IsCompilerGenerated;
613 		}
614 
TypeSize(TypeNode type)615 		public int TypeSize (TypeNode type)
616 		{
617 			int classSize = type.ClassSize;
618 			if (classSize > 0)
619 				return classSize;
620 			int size = TypeSizeHelper (type);
621 			type.ClassSize = size;
622 			return size;
623 		}
624 
Name(Local local)625 		public string Name (Local local)
626 		{
627 			return local.Name;
628 		}
629 
TypeSizeHelper(TypeNode type)630 		private int TypeSizeHelper (TypeNode type)
631 		{
632 			if (IsManagedPointer (type))
633 				return 4;
634 			if (type == System_Boolean)
635 				return 1;
636 			if (type == System_Char)
637 				return 2;
638 			if (type == System_Int8)
639 				return 1;
640 			if (type == System_Int16)
641 				return 2;
642 			if (type == System_Int32)
643 				return 4;
644 			if (type == System_Int64)
645 				return 8;
646 			if (type == System_IntPtr || type == System_Object || type == System_String || type == System_Type)
647 				return 4;
648 
649 			if (type == System_UInt8)
650 				return 1;
651 			if (type == System_UInt16)
652 				return 2;
653 			if (type == System_UInt32)
654 				return 4;
655 			if (type == System_UInt64)
656 				return 8;
657 
658 			if (type == System_UIntPtr || type == System_Single)
659 				return 4;
660 			if (type == System_Double)
661 				return 8;
662 
663 			return -1;
664 		}
665 
IsEnum(TypeNode type)666 		private bool IsEnum (TypeNode type)
667 		{
668 			return type.IsEnum;
669 		}
670 		#endregion
671 
TryLoadContractNodes(ref AssemblyNode assembly)672 		private bool TryLoadContractNodes (ref AssemblyNode assembly)
673 		{
674 			ContractNodes nodes = null;
675 			foreach (Module module in assembly.Modules) {
676 				IAssemblyResolver assemblyResolver = module.Definition.AssemblyResolver;
677 				foreach (AssemblyNameReference reference in module.Definition.AssemblyReferences) {
678 					AssemblyDefinition def = assemblyResolver.Resolve (reference);
679 					nodes = ContractNodes.GetContractNodes (new AssemblyNode (def), (s) => { });
680 					if (nodes != null)
681 						break;
682 				}
683 			}
684 
685 			if (nodes == null)
686 				return false;
687 
688 			var extractor = new ContractExtractor (nodes, assembly, true);
689 			assembly = (AssemblyNode) extractor.Visit (assembly);
690 			return true;
691 		}
692 	}
693 }
694