Merge pull request #963 from kebby/master
[mono.git] / mcs / ilasm / codegen / ExternTable.cs
1 //
2 // Mono.ILASM.ExternTable.cs
3 //
4 // Author(s):
5 //  Jackson Harper (Jackson@LatitudeGeo.com)
6 //
7 // (C) 2003 Jackson Harper, All rights reserved
8 //
9
10 using System;
11 using System.Collections;
12 using System.Collections.Generic;
13 using System.Reflection;
14 using System.Security;
15 using System.Globalization;
16 using PEAPI;
17
18 namespace Mono.ILASM {
19
20         public interface IScope {
21                 ExternTypeRef GetTypeRef (string full_name, bool is_valuetype);
22                 PEAPI.ClassRef GetType (string full_name, bool is_valuetype);
23                 string FullName { get; }
24         }
25         
26         public abstract class ExternRef : ICustomAttrTarget, IScope {
27
28                 protected string name;
29                 protected Hashtable class_table;
30                 protected Hashtable typeref_table;
31                 protected ArrayList customattr_list;
32                 protected bool is_resolved;
33
34                 public abstract void Resolve (CodeGen codegen);
35                 public abstract PEAPI.IExternRef GetExternRef ();
36
37                 public ExternRef (string name)
38                 {
39                         this.name = name;
40                         typeref_table = new Hashtable ();
41                         class_table = new Hashtable ();
42                 }
43
44                 public string Name {
45                         get { return name; }
46                 }
47
48                 public virtual string FullName {
49                         get { return name; }
50                 }
51
52                 public void AddCustomAttribute (CustomAttr customattr)
53                 {
54                         if (customattr_list == null)
55                                 customattr_list = new ArrayList ();
56
57                         customattr_list.Add (customattr);
58                 }
59
60                 public ExternTypeRef GetTypeRef (string full_name, bool is_valuetype)
61                 {
62                         string first= full_name;
63                         string rest = "";
64                         int slash = full_name.IndexOf ('/');
65                         if (slash > 0) {
66                                 first = full_name.Substring (0, slash);
67                                 rest = full_name.Substring (slash + 1);
68                         }
69                                 
70                         ExternTypeRef type_ref = typeref_table [first] as ExternTypeRef;
71                         
72                         if (type_ref != null) {
73                                 if (is_valuetype && rest == "")
74                                         type_ref.MakeValueClass ();
75                         } else {
76                                 type_ref = new ExternTypeRef (this, first, is_valuetype);
77                                 typeref_table [first] = type_ref;
78                         }
79
80                         return (rest == "" ? type_ref : type_ref.GetTypeRef (rest, is_valuetype));
81                 }
82
83                 public PEAPI.ClassRef GetType (string full_name, bool is_valuetype)
84                 {
85                         PEAPI.ClassRef klass = class_table[full_name] as PEAPI.ClassRef;
86                         
87                         if (klass != null)
88                                 return klass;
89
90                         string name_space, name;
91                         ExternTable.GetNameAndNamespace (full_name, out name_space, out name);
92
93                         if (is_valuetype)
94                                 klass = (PEAPI.ClassRef) GetExternRef ().AddValueClass (name_space, name);
95                         else        
96                                 klass = (PEAPI.ClassRef) GetExternRef ().AddClass (name_space, name);
97
98                         class_table [full_name] = klass;
99                         return klass;
100                 }
101
102         }
103
104         public class ExternModule : ExternRef {
105
106                 public PEAPI.ModuleRef ModuleRef;
107
108                 public ExternModule (string name) : base (name)
109                 {
110                 }
111
112                 public override string FullName {
113                         get { 
114                                 //'name' field should not contain the [.module ]
115                                 //as its used for resolving
116                                 return String.Format ("[.module {0}]", name); 
117                         }
118                 }
119
120                 public override void Resolve (CodeGen codegen)
121                 {
122                         if (is_resolved)
123                                 return;
124
125                         ModuleRef = codegen.PEFile.AddExternModule (name);
126                         if (customattr_list != null)
127                                 foreach (CustomAttr customattr in customattr_list)
128                                         customattr.AddTo (codegen, ModuleRef);
129
130                         is_resolved = true;
131                 }
132
133                 
134                 public override PEAPI.IExternRef GetExternRef ()
135                 {
136                         return ModuleRef;
137                 }
138         }
139
140         public class ExternAssembly : ExternRef, IDeclSecurityTarget {
141                         
142                 public PEAPI.AssemblyRef AssemblyRef;
143
144                 private int major, minor, build, revision;
145                 private byte [] public_key;
146                 private byte [] public_key_token;
147                 private string locale;
148                 private byte [] hash;
149                 private DeclSecurity decl_sec;
150                 private AssemblyName asmb_name;
151                 //flags
152                 private PEAPI.AssemAttr attr;
153
154                 public ExternAssembly (string name, AssemblyName asmb_name, PEAPI.AssemAttr attr) : base (name)
155                 {
156                         this.name = name;
157                         this.asmb_name = asmb_name;
158                         this.attr = attr;
159                         major = minor = build = revision = -1;
160                 }
161
162                 public override string FullName {
163                         get { 
164                                 //'name' field should not contain the []
165                                 //as its used for resolving
166                                 return String.Format ("[{0}]", name); 
167                         }
168                 }
169
170                 public AssemblyName AssemblyName {
171                         get { return asmb_name; }
172                 }
173
174                 public DeclSecurity DeclSecurity {
175                         get {
176                                 if (decl_sec == null)
177                                         decl_sec = new DeclSecurity ();
178                                 return decl_sec;
179                         }
180                 }
181
182                 public override void Resolve (CodeGen code_gen)
183                 {
184                         if (is_resolved)
185                                 return;
186
187                         AssemblyRef = code_gen.PEFile.AddExternAssembly (name);
188                         AssemblyRef.AddAssemblyAttr (attr);
189                         if (major != -1)
190                                 AssemblyRef.AddVersionInfo (major, minor, build, revision);
191                         if (public_key != null)
192                                 AssemblyRef.AddKey (public_key);
193                         if (public_key_token != null)
194                                 AssemblyRef.AddKeyToken (public_key_token);
195                         if (locale != null)
196                                 AssemblyRef.AddCulture (locale);
197                         if (hash != null)
198                                 AssemblyRef.AddHash (hash);
199
200                         if (customattr_list != null)
201                                 foreach (CustomAttr customattr in customattr_list)
202                                         customattr.AddTo (code_gen, AssemblyRef);
203                                         
204                         if (decl_sec != null)
205                                 decl_sec.AddTo (code_gen, AssemblyRef);
206
207                         class_table = new Hashtable ();
208
209                         is_resolved = true;
210                 }
211
212                 public override PEAPI.IExternRef GetExternRef ()
213                 {
214                         return AssemblyRef;
215                 }
216                 
217                 public void SetVersion (int major, int minor, int build, int revision)
218                 {
219                         this.major = major;
220                         this.minor = minor;
221                         this.build = build;
222                         this.revision = revision;
223                         asmb_name.Version = new Version (major, minor, build, revision);
224                 }
225
226                 public void SetPublicKey (byte [] public_key)
227                 {
228                         this.public_key = public_key;
229                         asmb_name.SetPublicKey (public_key);
230                 }
231
232                 public void SetPublicKeyToken (byte [] public_key_token)
233                 {
234                         this.public_key_token = public_key_token;
235                         asmb_name.SetPublicKey (public_key);
236                 }
237
238                 public void SetLocale (string locale)
239                 {
240                         this.locale = locale;
241                         //FIXME: is this correct?
242                         asmb_name.CultureInfo = new CultureInfo (locale);
243                 }
244
245                 public void SetHash (byte [] hash)
246                 {
247                         this.hash = hash;
248                 }
249
250         }
251
252         public class ExternClass
253         {
254             string fullName;
255             TypeAttr ta;
256             string assemblyReference;
257
258             public ExternClass (string fullName, TypeAttr ta, string assemblyReference)
259             {
260                 this.fullName = fullName;
261                 this.ta = ta;
262                 this.assemblyReference = assemblyReference;
263             }
264
265             public void Resolve (CodeGen code_gen, ExternTable table)
266             {
267                 var ar = table.GetAssemblyRef (assemblyReference);
268                 if (ar != null) {
269                     string ns = null;
270                     string name = fullName;
271
272                     int pos = name.LastIndexOf ('.');
273                     if (pos > 0) {
274                         ns = name.Substring (0, pos);
275                         name = name.Substring (pos + 1);
276                     }
277  
278                     code_gen.PEFile.AddExternClass (ns, name, ta, ar.AssemblyRef);
279                 }
280             }
281         }
282
283         
284         public class ExternTable {
285
286                 Hashtable assembly_table;
287                 Hashtable module_table;
288                 List<ExternClass> class_table;
289
290                 bool is_resolved;
291                 
292                 public void AddCorlib ()
293                 {
294                         // Add mscorlib
295                         string mscorlib_name = "mscorlib";
296                         AssemblyName mscorlib = new AssemblyName ();
297                         mscorlib.Name = mscorlib_name;
298                         AddAssembly (mscorlib_name, mscorlib, 0);
299
300                         // Also need to alias corlib, normally corlib and
301                         // mscorlib are used interchangably
302                         assembly_table["corlib"] = assembly_table["mscorlib"];
303                 }
304
305                 public ExternAssembly AddAssembly (string name, AssemblyName asmb_name, PEAPI.AssemAttr attr)
306                 {
307                         ExternAssembly ea = null;
308
309                         if (assembly_table == null) {
310                                 assembly_table = new Hashtable ();
311                         } else {
312                                 ea = assembly_table [name] as ExternAssembly;
313                                 if (ea != null)
314                                         return ea;
315                         }
316
317                         ea = new ExternAssembly (name, asmb_name, attr);
318
319                         assembly_table [name] = ea;
320
321                         return ea;
322                 }
323
324                 public ExternModule AddModule (string name)
325                 {
326                         ExternModule em = null;
327
328                         if (module_table == null) {
329                                 module_table = new Hashtable ();
330                         } else {
331                                 em = module_table [name] as ExternModule;
332                                 if (em != null)
333                                         return em;
334                         }
335
336                         em = new ExternModule (name);
337
338                         module_table [name] = em;
339
340                         return em;
341                 }
342
343                 public void AddClass (string name, TypeAttr ta, string assemblyReference)
344                 {
345                     if (class_table == null)
346                         class_table = new List<ExternClass> ();
347
348                     class_table.Add (new ExternClass (name, ta, assemblyReference));
349                 }
350
351                 public void Resolve (CodeGen code_gen)
352                 {
353                         if (is_resolved)
354                                 return;
355
356                         if (assembly_table != null)
357                                 foreach (ExternAssembly ext in assembly_table.Values)
358                                         ext.Resolve (code_gen);
359
360                         if (module_table != null)
361                             foreach (ExternModule ext in module_table.Values)
362                                     ext.Resolve (code_gen);
363
364                         if (class_table != null)
365                             foreach (var entry in class_table)
366                                 entry.Resolve (code_gen, this);
367
368                         is_resolved = true;     
369                 }
370
371                 public ExternTypeRef GetTypeRef (string asmb_name, string full_name, bool is_valuetype)
372                 {
373                         ExternAssembly ext_asmb = null;
374                         if (assembly_table == null && (asmb_name == "mscorlib" || asmb_name == "corlib")) {
375                                 /* AddCorlib if mscorlib is being referenced but
376                                    we haven't encountered a ".assembly 'name'" as yet. */
377                                 Report.Warning (String.Format ("Reference to undeclared extern assembly '{0}', adding.", asmb_name));
378                                 AddCorlib ();
379                         }
380                         if (assembly_table != null)
381                                 ext_asmb = assembly_table[asmb_name] as ExternAssembly;
382
383                         if (ext_asmb == null) {
384                                 System.Reflection.AssemblyName asmname = new System.Reflection.AssemblyName ();
385                                 asmname.Name = asmb_name;
386
387                                 Report.Warning (String.Format ("Reference to undeclared extern assembly '{0}', adding.", asmb_name));
388                                 ext_asmb = AddAssembly (asmb_name, asmname, 0);
389                         }
390
391                         return ext_asmb.GetTypeRef (full_name, is_valuetype);
392                 }
393
394                 public ExternTypeRef GetModuleTypeRef (string mod_name, string full_name, bool is_valuetype)
395                 {
396                         ExternModule mod = null;
397                         if (module_table != null)
398                                 mod = module_table [mod_name] as ExternModule;
399
400                         if (mod == null)
401                                 Report.Error ("Module " + mod_name + " not defined.");
402
403                         return mod.GetTypeRef (full_name, is_valuetype);
404                 }
405
406                 public ExternAssembly GetAssemblyRef (string assembly_name)
407                 {
408                         ExternAssembly ass = null;
409                         if (assembly_table != null)
410                                 ass = assembly_table [assembly_name] as ExternAssembly;
411
412                         if (ass == null)
413                                 Report.Error ("Assembly " + assembly_name + " is not defined.");
414
415                         return ass;
416                 }
417
418                 public static void GetNameAndNamespace (string full_name,
419                         out string name_space, out string name) {
420
421                         int last_dot = full_name.LastIndexOf ('.');
422
423                         if (last_dot < 0) {
424                                 name_space = String.Empty;
425                                 name = full_name;
426                                 return;
427                         }
428
429                         name_space = full_name.Substring (0, last_dot);
430                         name = full_name.Substring (last_dot + 1);
431                 }
432
433         }
434 }
435