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