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