Less static is good for my health
[mono.git] / mcs / mcs / reflection.cs
1 //
2 // reflection.cs: System.Reflection and System.Reflection.Emit specific implementations
3 //
4 // Author: Marek Safar (marek.safar@gmail.com)
5 //
6 // Dual licensed under the terms of the MIT X11 or GNU GPL
7 //
8 // Copyright 2009-2010 Novell, Inc. 
9 //
10 //
11
12 using System;
13 using System.Collections.Generic;
14 using System.Reflection;
15 using System.IO;
16 using System.Runtime.CompilerServices;
17 using System.Reflection.Emit;
18 using System.Security;
19
20 namespace Mono.CSharp
21 {
22 #if STATIC
23         public class ReflectionImporter
24         {
25                 public ReflectionImporter (BuildinTypes buildin)
26                 {
27                         throw new NotSupportedException ();
28                 }
29
30                 public void ImportAssembly (Assembly assembly, RootNamespace targetNamespace)
31                 {
32                         throw new NotSupportedException ();
33                 }
34
35                 public ImportedModuleDefinition ImportModule (Module module, RootNamespace targetNamespace)
36                 {
37                         throw new NotSupportedException ();
38                 }
39
40                 public TypeSpec ImportType (Type type)
41                 {
42                         throw new NotSupportedException ();
43                 }
44         }
45 #else
46         public sealed class ReflectionImporter : MetadataImporter
47         {
48                 public ReflectionImporter (BuildinTypes buildin)
49                 {
50                         Initialize (buildin);
51                 }
52
53                 public override void AddCompiledType (TypeBuilder builder, TypeSpec spec)
54                 {
55                 }
56
57                 protected override MemberKind DetermineKindFromBaseType (Type baseType)
58                 {
59                         if (baseType == typeof (ValueType))
60                                 return MemberKind.Struct;
61
62                         if (baseType == typeof (System.Enum))
63                                 return MemberKind.Enum;
64
65                         if (baseType == typeof (MulticastDelegate))
66                                 return MemberKind.Delegate;
67
68                         return MemberKind.Class;
69                 }
70
71                 public override void GetCustomAttributeTypeName (CustomAttributeData cad, out string typeNamespace, out string typeName)
72                 {
73                         var dt = cad.Constructor.DeclaringType;
74                         typeNamespace = dt.Namespace;
75                         typeName = dt.Name;
76                 }
77
78                 protected override bool HasVolatileModifier (Type[] modifiers)
79                 {
80                         foreach (var t in modifiers) {
81                                 if (t == typeof (IsVolatile))
82                                         return true;
83                         }
84
85                         return false;
86                 }
87
88                 public void ImportAssembly (Assembly assembly, RootNamespace targetNamespace)
89                 {
90                         // It can be used more than once when importing same assembly
91                         // into 2 or more global aliases
92                         var definition = GetAssemblyDefinition (assembly);
93
94                         //
95                         // This part tries to simulate loading of top-level
96                         // types only, any missing dependencies are ignores here.
97                         // Full error report is reported later when the type is
98                         // actually used
99                         //
100                         Type[] all_types;
101                         try {
102                                 all_types = assembly.GetTypes ();
103                         } catch (ReflectionTypeLoadException e) {
104                                 all_types = e.Types;
105                         }
106
107                         ImportTypes (all_types, targetNamespace, definition.HasExtensionMethod);
108                 }
109
110                 public ImportedModuleDefinition ImportModule (Module module, RootNamespace targetNamespace)
111                 {
112                         var module_definition = new ImportedModuleDefinition (module, this);
113                         module_definition.ReadAttributes ();
114
115                         Type[] all_types;
116                         try {
117                                 all_types = module.GetTypes ();
118                         } catch (ReflectionTypeLoadException e) {
119                                 all_types = e.Types;
120                         }
121
122                         ImportTypes (all_types, targetNamespace, false);
123
124                         return module_definition;
125                 }
126
127                 void Initialize (BuildinTypes buildin)
128                 {
129                         //
130                         // Setup mapping for build-in types to avoid duplication of their definition
131                         //
132                         compiled_types.Add (typeof (object), buildin.Object);
133                         compiled_types.Add (typeof (System.ValueType), buildin.ValueType);
134                         compiled_types.Add (typeof (System.Attribute), buildin.Attribute);
135
136                         compiled_types.Add (typeof (int), buildin.Int);
137                         compiled_types.Add (typeof (long), buildin.Long);
138                         compiled_types.Add (typeof (uint), buildin.UInt);
139                         compiled_types.Add (typeof (ulong), buildin.ULong);
140                         compiled_types.Add (typeof (byte), buildin.Byte);
141                         compiled_types.Add (typeof (sbyte), buildin.SByte);
142                         compiled_types.Add (typeof (short), buildin.Short);
143                         compiled_types.Add (typeof (ushort), buildin.UShort);
144
145                         compiled_types.Add (typeof (System.Collections.IEnumerator), buildin.IEnumerator);
146                         compiled_types.Add (typeof (System.Collections.IEnumerable), buildin.IEnumerable);
147                         compiled_types.Add (typeof (System.IDisposable), buildin.IDisposable);
148
149                         compiled_types.Add (typeof (char), buildin.Char);
150                         compiled_types.Add (typeof (string), buildin.String);
151                         compiled_types.Add (typeof (float), buildin.Float);
152                         compiled_types.Add (typeof (double), buildin.Double);
153                         compiled_types.Add (typeof (decimal), buildin.Decimal);
154                         compiled_types.Add (typeof (bool), buildin.Bool);
155                         compiled_types.Add (typeof (System.IntPtr), buildin.IntPtr);
156                         compiled_types.Add (typeof (System.UIntPtr), buildin.UIntPtr);
157
158                         compiled_types.Add (typeof (System.MulticastDelegate), buildin.MulticastDelegate);
159                         compiled_types.Add (typeof (System.Delegate), buildin.Delegate);
160                         compiled_types.Add (typeof (System.Enum), buildin.Enum);
161                         compiled_types.Add (typeof (System.Array), buildin.Array);
162                         compiled_types.Add (typeof (void), buildin.Void);
163                         compiled_types.Add (typeof (System.Type), buildin.Type);
164                         compiled_types.Add (typeof (System.Exception), buildin.Exception);
165                         compiled_types.Add (typeof (System.RuntimeFieldHandle), buildin.RuntimeFieldHandle);
166                         compiled_types.Add (typeof (System.RuntimeTypeHandle), buildin.RuntimeTypeHandle);
167                 }
168         }
169
170         [System.Runtime.InteropServices.StructLayout (System.Runtime.InteropServices.LayoutKind.Explicit)]
171         struct SingleConverter
172         {
173                 [System.Runtime.InteropServices.FieldOffset (0)]
174                 int i;
175                 [System.Runtime.InteropServices.FieldOffset (0)]
176                 float f;
177
178                 public static int SingleToInt32Bits (float v)
179                 {
180                         SingleConverter c = new SingleConverter ();
181                         c.f = v;
182                         return c.i;
183                 }
184         }
185
186 #endif
187
188         public class AssemblyDefinitionDynamic : AssemblyDefinition
189         {
190                 //
191                 // In-memory only assembly container
192                 //
193                 public AssemblyDefinitionDynamic (ModuleContainer module, string name)
194                         : base (module, name)
195                 {
196                 }
197
198                 //
199                 // Assembly container with file output
200                 //
201                 public AssemblyDefinitionDynamic (ModuleContainer module, string name, string fileName)
202                         : base (module, name, fileName)
203                 {
204                 }
205
206                 public Module IncludeModule (string moduleFile)
207                 {
208                         return builder_extra.AddModule (moduleFile);
209                 }
210
211 #if !STATIC
212                 public override ModuleBuilder CreateModuleBuilder ()
213                 {
214                         if (file_name == null)
215                                 return Builder.DefineDynamicModule (Name, false);
216
217                         return base.CreateModuleBuilder ();
218                 }
219 #endif
220                 //
221                 // Initializes the code generator
222                 //
223                 public bool Create (AppDomain domain, AssemblyBuilderAccess access)
224                 {
225 #if STATIC
226                         throw new NotSupportedException ();
227 #else
228                         ResolveAssemblySecurityAttributes ();
229                         var an = CreateAssemblyName ();
230
231                         Builder = file_name == null ?
232                                 domain.DefineDynamicAssembly (an, access) :
233                                 domain.DefineDynamicAssembly (an, access, Dirname (file_name));
234
235                         module.Create (this, CreateModuleBuilder ());
236                         builder_extra = new AssemblyBuilderMonoSpecific (Builder, Compiler);
237                         return true;
238 #endif
239                 }
240
241                 static string Dirname (string name)
242                 {
243                         int pos = name.LastIndexOf ('/');
244
245                         if (pos != -1)
246                                 return name.Substring (0, pos);
247
248                         pos = name.LastIndexOf ('\\');
249                         if (pos != -1)
250                                 return name.Substring (0, pos);
251
252                         return ".";
253                 }
254
255 #if !STATIC
256                 protected override void SaveModule (PortableExecutableKinds pekind, ImageFileMachine machine)
257                 {
258                         try {
259                                 var module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
260                                 var set_module_only = module_only.GetSetMethod (true);
261
262                                 set_module_only.Invoke (Builder, new object[] { true });
263                         } catch {
264                                 base.SaveModule (pekind, machine);
265                         }
266
267                         Builder.Save (file_name, pekind, machine);
268                 }
269 #endif
270         }
271
272         //
273         // Extension to System.Reflection.Emit.AssemblyBuilder to have fully compatible
274         // compiler
275         //
276         class AssemblyBuilderMonoSpecific : AssemblyBuilderExtension
277         {
278                 static MethodInfo adder_method;
279                 static MethodInfo add_permission;
280                 static MethodInfo add_type_forwarder;
281                 static MethodInfo win32_icon_define;
282                 static FieldInfo assembly_version;
283                 static FieldInfo assembly_algorithm;
284                 static FieldInfo assembly_culture;
285                 static FieldInfo assembly_flags;
286
287                 AssemblyBuilder builder;
288
289                 public AssemblyBuilderMonoSpecific (AssemblyBuilder ab, CompilerContext ctx)
290                         : base (ctx)
291                 {
292                         this.builder = ab;
293                 }
294
295                 public override Module AddModule (string module)
296                 {
297                         try {
298                                 if (adder_method == null)
299                                         adder_method = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance | BindingFlags.NonPublic);
300
301                                 return (Module) adder_method.Invoke (builder, new object[] { module });
302                         } catch {
303                                 return base.AddModule (module);
304                         }
305                 }
306
307                 public override void AddPermissionRequests (PermissionSet[] permissions)
308                 {
309                         try {
310                                 if (add_permission == null)
311                                         add_permission = typeof (AssemblyBuilder).GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
312
313                                 add_permission.Invoke (builder, permissions);
314                         } catch {
315                                 base.AddPermissionRequests (permissions);
316                         }
317                 }
318
319                 public override void AddTypeForwarder (TypeSpec type, Location loc)
320                 {
321                         try {
322                                 if (add_type_forwarder == null) {
323                                         add_type_forwarder = typeof (AssemblyBuilder).GetMethod ("AddTypeForwarder", BindingFlags.NonPublic | BindingFlags.Instance);
324                                 }
325
326                                 add_type_forwarder.Invoke (builder, new object[] { type.GetMetaInfo () });
327                         } catch {
328                                 base.AddTypeForwarder (type, loc);
329                         }
330                 }
331
332                 public override void DefineWin32IconResource (string fileName)
333                 {
334                         try {
335                                 if (win32_icon_define == null)
336                                         win32_icon_define = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance | BindingFlags.NonPublic);
337
338                                 win32_icon_define.Invoke (builder, new object[] { fileName });
339                         } catch {
340                                 base.DefineWin32IconResource (fileName);
341                         }
342                 }
343
344                 public override void SetAlgorithmId (uint value, Location loc)
345                 {
346                         try {
347                                 if (assembly_algorithm == null)
348                                         assembly_algorithm = typeof (AssemblyBuilder).GetField ("algid", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField);
349
350                                 assembly_algorithm.SetValue (builder, value);
351                         } catch {
352                                 base.SetAlgorithmId (value, loc);
353                         }
354                 }
355
356                 public override void SetCulture (string culture, Location loc)
357                 {
358                         try {
359                                 if (assembly_culture == null)
360                                         assembly_culture = typeof (AssemblyBuilder).GetField ("culture", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField);
361
362                                 assembly_culture.SetValue (builder, culture);
363                         } catch {
364                                 base.SetCulture (culture, loc);
365                         }
366                 }
367
368                 public override void SetFlags (uint flags, Location loc)
369                 {
370                         try {
371                                 if (assembly_flags == null)
372                                         assembly_flags = typeof (AssemblyBuilder).GetField ("flags", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField);
373
374                                 assembly_flags.SetValue (builder, flags);
375                         } catch {
376                                 base.SetFlags (flags, loc);
377                         }
378                 }
379
380                 public override void SetVersion (Version version, Location loc)
381                 {
382                         try {
383                                 if (assembly_version == null)
384                                         assembly_version = typeof (AssemblyBuilder).GetField ("version", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField);
385
386                                 assembly_version.SetValue (builder, version.ToString (4));
387                         } catch {
388                                 base.SetVersion (version, loc);
389                         }
390                 }
391         }
392
393         //
394         // Reflection based references loader
395         //
396         class DynamicLoader : AssemblyReferencesLoader<Assembly>
397         {
398                 readonly ReflectionImporter importer;
399
400                 public DynamicLoader (ReflectionImporter importer, CompilerContext compiler)
401                         : base (compiler)
402                 {
403                         paths.Add (GetSystemDir ());
404
405                         this.importer = importer;
406                 }
407
408                 public ReflectionImporter Importer {
409                         get {
410                                 return importer;
411                         }
412                 }
413
414                 protected override string[] GetDefaultReferences ()
415                 {
416                         //
417                         // For now the "default config" is harcoded into the compiler
418                         // we can move this outside later
419                         //
420                         var default_references = new List<string> (8);
421
422                         default_references.Add ("System");
423                         default_references.Add ("System.Xml");
424 #if NET_2_1
425                         default_references.Add ("System.Net");
426                         default_references.Add ("System.Windows");
427                         default_references.Add ("System.Windows.Browser");
428 #endif
429
430                         if (compiler.Settings.Version > LanguageVersion.ISO_2)
431                                 default_references.Add ("System.Core");
432                         if (compiler.Settings.Version > LanguageVersion.V_3)
433                                 default_references.Add ("Microsoft.CSharp");
434
435                         return default_references.ToArray ();
436                 }
437
438                 //
439                 // Returns the directory where the system assemblies are installed
440                 //
441                 static string GetSystemDir ()
442                 {
443                         return Path.GetDirectoryName (typeof (object).Assembly.Location);
444                 }
445
446                 public override bool HasObjectType (Assembly assembly)
447                 {
448                         return assembly.GetType (compiler.BuildinTypes.Object.FullName) != null;
449                 }
450
451                 public override Assembly LoadAssemblyFile (string fileName)
452                 {
453                         return LoadAssemblyFile (fileName, false);
454                 }
455
456                 Assembly LoadAssemblyFile (string assembly, bool soft)
457                 {
458                         Assembly a = null;
459
460                         try {
461                                 try {
462                                         char[] path_chars = { '/', '\\' };
463
464                                         if (assembly.IndexOfAny (path_chars) != -1) {
465                                                 a = Assembly.LoadFrom (assembly);
466                                         } else {
467                                                 string ass = assembly;
468                                                 if (ass.EndsWith (".dll") || ass.EndsWith (".exe"))
469                                                         ass = assembly.Substring (0, assembly.Length - 4);
470                                                 a = Assembly.Load (ass);
471                                         }
472                                 } catch (FileNotFoundException) {
473                                         bool err = !soft;
474                                         foreach (string dir in paths) {
475                                                 string full_path = Path.Combine (dir, assembly);
476                                                 if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
477                                                         full_path += ".dll";
478
479                                                 try {
480                                                         a = Assembly.LoadFrom (full_path);
481                                                         err = false;
482                                                         break;
483                                                 } catch (FileNotFoundException) {
484                                                 }
485                                         }
486
487                                         if (err) {
488                                                 Error_FileNotFound (assembly);
489                                                 return a;
490                                         }
491                                 }
492                         } catch (BadImageFormatException) {
493                                 Error_FileCorrupted (assembly);
494                         }
495
496                         return a;
497                 }
498
499                 public override Assembly LoadAssemblyDefault (string fileName)
500                 {
501                         return LoadAssemblyFile (fileName, true);
502                 }
503
504                 Module LoadModuleFile (AssemblyDefinitionDynamic assembly, string module)
505                 {
506                         string total_log = "";
507
508                         try {
509                                 try {
510                                         return assembly.IncludeModule (module);
511                                 } catch (FileNotFoundException) {
512                                         bool err = true;
513                                         foreach (string dir in paths) {
514                                                 string full_path = Path.Combine (dir, module);
515                                                 if (!module.EndsWith (".netmodule"))
516                                                         full_path += ".netmodule";
517
518                                                 try {
519                                                         return assembly.IncludeModule (full_path);
520                                                 } catch (FileNotFoundException ff) {
521                                                         total_log += ff.FusionLog;
522                                                 }
523                                         }
524                                         if (err) {
525                                                 Error_FileNotFound (module);
526                                                 return null;
527                                         }
528                                 }
529                         } catch (BadImageFormatException) {
530                                 Error_FileCorrupted (module);
531                         }
532
533                         return null;
534                 }
535
536                 public void LoadModules (AssemblyDefinitionDynamic assembly, RootNamespace targetNamespace)
537                 {
538                         foreach (var moduleName in compiler.Settings.Modules) {
539                                 var m = LoadModuleFile (assembly, moduleName);
540                                 if (m == null)
541                                         continue;
542
543                                 var md = importer.ImportModule (m, targetNamespace);
544                                 assembly.AddModule (md);
545                         }
546                 }
547
548                 public override void LoadReferences (ModuleContainer module)
549                 {
550                         Assembly corlib;
551                         List<Tuple<RootNamespace, Assembly>> loaded;
552                         base.LoadReferencesCore (module, out corlib, out loaded);
553
554                         if (corlib == null)
555                                 return;
556
557                         importer.ImportAssembly (corlib, module.GlobalRootNamespace);
558                         foreach (var entry in loaded) {
559                                 importer.ImportAssembly (entry.Item2, entry.Item1);
560                         }
561                 }
562         }
563 }