Merge branch 'master' of github.com:mono/mono into masterwork
[mono.git] / mcs / mcs / roottypes.cs
1 //
2 // roottypes.cs: keeps a tree representation of the generated code
3 //
4 // Authors: Miguel de Icaza (miguel@gnu.org)
5 //          Marek Safar  (marek.safar@gmail.com)
6 //
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
8 //
9 // Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 // Copyright 2003-2008 Novell, Inc.
11 //
12
13 using System;
14 using System.Collections.Generic;
15 using System.Reflection;
16 using System.Reflection.Emit;
17 using System.Runtime.InteropServices;
18 using Mono.CompilerServices.SymbolWriter;
19
20 namespace Mono.CSharp
21 {
22         //
23         // Module (top-level type) container
24         //
25         public class ModuleContainer : TypeContainer
26         {
27                 public CharSet DefaultCharSet = CharSet.Ansi;
28                 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
29
30                 Dictionary<int, List<AnonymousTypeClass>> anonymous_types;
31
32                 AssemblyDefinition assembly;
33                 readonly CompilerContext context;
34                 readonly RootNamespace global_ns;
35                 Dictionary<string, RootNamespace> alias_ns;
36
37                 ModuleBuilder builder;
38                 int static_data_counter;
39
40                 // HACK
41                 public List<Enum> hack_corlib_enums = new List<Enum> ();
42
43                 bool has_default_charset;
44                 bool has_extenstion_method;
45
46                 PredefinedAttributes predefined_attributes;
47                 PredefinedTypes predefined_types;
48
49                 static readonly string[] attribute_targets = new string[] { "assembly", "module" };
50
51                 public ModuleContainer (CompilerContext context)
52                         : base (null, null, MemberName.Null, null, 0)
53                 {
54                         this.context = context;
55
56                         caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected);
57
58                         types = new List<TypeContainer> ();
59                         anonymous_types = new Dictionary<int, List<AnonymousTypeClass>> ();
60                         global_ns = new GlobalRootNamespace ();
61                         alias_ns = new Dictionary<string, RootNamespace> ();
62                 }
63
64                 #region Properties
65
66                 public override AttributeTargets AttributeTargets {
67                         get {
68                                 return AttributeTargets.Assembly;
69                         }
70                 }
71
72                 public ModuleBuilder Builder {
73                         get {
74                                 return builder;
75                         }
76                 }
77
78                 public override CompilerContext Compiler {
79                         get {
80                                 return context;
81                         }
82                 }
83
84                 public override AssemblyDefinition DeclaringAssembly {
85                         get {
86                                 return assembly;
87                         }
88                 }
89
90                 public bool HasDefaultCharSet {
91                         get {
92                                 return has_default_charset;
93                         }
94                 }
95
96                 public bool HasExtensionMethod {
97                         get {
98                                 return has_extenstion_method;
99                         }
100                         set {
101                                 has_extenstion_method = value;
102                         }
103                 }
104
105                 //
106                 // Returns module global:: namespace
107                 //
108                 public RootNamespace GlobalRootNamespace {
109                     get {
110                         return global_ns;
111                     }
112                 }
113
114                 public override ModuleContainer Module {
115                         get {
116                                 return this;
117                         }
118                 }
119
120                 internal PredefinedAttributes PredefinedAttributes {
121                         get {
122                                 return predefined_attributes;
123                         }
124                 }
125
126                 internal PredefinedTypes PredefinedTypes {
127                         get {
128                                 return predefined_types;
129                         }
130                 }
131
132                 public override string[] ValidAttributeTargets {
133                         get {
134                                 return attribute_targets;
135                         }
136                 }
137
138                 #endregion
139
140                 public void AddAnonymousType (AnonymousTypeClass type)
141                 {
142                         List<AnonymousTypeClass> existing;
143                         if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing))
144                         if (existing == null) {
145                                 existing = new List<AnonymousTypeClass> ();
146                                 anonymous_types.Add (type.Parameters.Count, existing);
147                         }
148
149                         existing.Add (type);
150                 }
151
152                 public void AddAttributes (List<Attribute> attrs)
153                 {
154                         AddAttributes (attrs, this);
155                 }
156
157                 public void AddAttributes (List<Attribute> attrs, IMemberContext context)
158                 {
159                         foreach (Attribute a in attrs)
160                                 a.AttachTo (this, context);
161
162                         if (attributes == null) {
163                                 attributes = new Attributes (attrs);
164                                 return;
165                         }
166                         attributes.AddAttributes (attrs);
167                 }
168
169                 public override TypeContainer AddPartial (TypeContainer nextPart)
170                 {
171                         return AddPartial (nextPart, nextPart.Name);
172                 }
173
174                 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
175                 {
176                         if (a.Target == AttributeTargets.Assembly) {
177                                 assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
178                                 return;
179                         }
180
181                         if (a.Type == pa.CLSCompliant) {
182                                 Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
183                                 if (cls == null) {
184                                         Report.Warning (3012, 1, a.Location,
185                                                 "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
186                                 } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) {
187                                         Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ());
188                                         Report.Warning (3017, 1, a.Location,
189                                                 "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
190                                         return;
191                                 }
192                         }
193
194                         builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
195                 }
196
197                 public new void CloseType ()
198                 {
199                         HackCorlibEnums ();
200
201                         foreach (TypeContainer tc in types) {
202                                 tc.CloseType ();
203                         }
204
205                         if (compiler_generated != null)
206                                 foreach (CompilerGeneratedClass c in compiler_generated)
207                                         c.CloseType ();
208
209                         //
210                         // If we have a <PrivateImplementationDetails> class, close it
211                         //
212                         if (TypeBuilder != null) {
213                                 var cg = PredefinedAttributes.CompilerGenerated;
214                                 cg.EmitAttribute (TypeBuilder);
215                                 TypeBuilder.CreateType ();
216                         }
217                 }
218
219                 public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
220                 {
221                         return builder.DefineType (name, attr, null, typeSize);
222                 }
223
224                 //
225                 // Creates alias global namespace
226                 //
227                 public RootNamespace CreateRootNamespace (string alias)
228                 {
229                         if (alias == global_ns.Alias) {
230                                 NamespaceEntry.Error_GlobalNamespaceRedefined (Location.Null, Report);
231                                 return global_ns;
232                         }
233
234                         RootNamespace rn;
235                         if (!alias_ns.TryGetValue (alias, out rn)) {
236                                 rn = new RootNamespace (alias);
237                                 alias_ns.Add (alias, rn);
238                         }
239
240                         return rn;
241                 }
242
243                 public new void Define ()
244                 {
245                         builder = assembly.CreateModuleBuilder ();
246
247                         // FIXME: Temporary hack for repl to reset
248                         TypeBuilder = null;
249
250                         // TODO: It should be done much later when the types are resolved
251                         // but that require DefineType clean-up
252                         ResolveGlobalAttributes ();
253
254                         foreach (TypeContainer tc in types)
255                                 tc.CreateType ();
256
257                         InitializePredefinedTypes ();
258
259                         foreach (TypeContainer tc in types)
260                                 tc.DefineType ();
261
262                         foreach (TypeContainer tc in types)
263                                 tc.ResolveTypeParameters ();
264
265                         foreach (TypeContainer tc in types) {
266                                 try {
267                                         tc.Define ();
268                                 } catch (Exception e) {
269                                         throw new InternalErrorException (tc, e);
270                                 }
271                         }
272                 }
273
274                 public override void Emit ()
275                 {
276                         if (OptAttributes != null)
277                                 OptAttributes.Emit ();
278
279                         if (RootContext.Unsafe) {
280                                 var pa = PredefinedAttributes.UnverifiableCode;
281                                 if (pa.IsDefined)
282                                         pa.EmitAttribute (builder);
283                         }
284
285                         foreach (var tc in types)
286                                 tc.DefineConstants ();
287
288                         HackCorlib ();
289
290                         foreach (TypeContainer tc in types)
291                                 tc.EmitType ();
292
293                         if (Compiler.Report.Errors > 0)
294                                 return;
295
296                         foreach (TypeContainer tc in types)
297                                 tc.VerifyMembers ();
298
299                         if (compiler_generated != null)
300                                 foreach (var c in compiler_generated)
301                                         c.EmitType ();
302                 }
303
304                 public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
305                 {
306                         List<AnonymousTypeClass> candidates;
307                         if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
308                                 return null;
309
310                         int i;
311                         foreach (AnonymousTypeClass at in candidates) {
312                                 for (i = 0; i < parameters.Count; ++i) {
313                                         if (!parameters [i].Equals (at.Parameters [i]))
314                                                 break;
315                                 }
316
317                                 if (i == parameters.Count)
318                                         return at;
319                         }
320
321                         return null;
322                 }
323
324                 public RootNamespace GetRootNamespace (string name)
325                 {
326                         RootNamespace rn;
327                         alias_ns.TryGetValue (name, out rn);
328                         return rn;
329                 }
330
331                 public override string GetSignatureForError ()
332                 {
333                         return "<module>";
334                 }
335
336                 void HackCorlib ()
337                 {
338                         if (RootContext.StdLib)
339                                 return;
340
341                         //
342                         // HACK: When building corlib mcs uses loaded mscorlib which
343                         // has different predefined types and this method sets mscorlib types
344                         // to be same to avoid type check errors in CreateType.
345                         //
346                         var type = typeof (Type);
347                         var system_4_type_arg = new[] { type, type, type, type };
348
349                         MethodInfo set_corlib_type_builders =
350                                 typeof (System.Reflection.Emit.AssemblyBuilder).GetMethod (
351                                 "SetCorlibTypeBuilders", BindingFlags.NonPublic | BindingFlags.Instance, null,
352                                 system_4_type_arg, null);
353
354                         if (set_corlib_type_builders == null) {
355                                 Compiler.Report.Warning (-26, 3,
356                                         "The compilation may fail due to missing `System.Reflection.Emit.AssemblyBuilder.SetCorlibTypeBuilders(...)' method");
357                                 return;
358                         }
359
360                         object[] args = new object[4];
361                         args[0] = TypeManager.object_type.GetMetaInfo ();
362                         args[1] = TypeManager.value_type.GetMetaInfo ();
363                         args[2] = TypeManager.enum_type.GetMetaInfo ();
364                         args[3] = TypeManager.void_type.GetMetaInfo ();
365                         set_corlib_type_builders.Invoke (assembly.Builder, args);
366                 }
367
368                 void HackCorlibEnums ()
369                 {
370                         if (RootContext.StdLib)
371                                 return;
372
373                         // Another Mono corlib HACK
374                         // mono_class_layout_fields requires to have enums created
375                         // before creating a class which used the enum for any of its fields
376                         foreach (var e in hack_corlib_enums)
377                                 e.CloseType ();
378                 }
379
380                 public void InitializePredefinedTypes ()
381                 {
382                         predefined_attributes = new PredefinedAttributes (this);
383                         predefined_types = new PredefinedTypes (this);
384                 }
385
386                 public override bool IsClsComplianceRequired ()
387                 {
388                         return DeclaringAssembly.IsCLSCompliant;
389                 }
390                 
391                 public AssemblyDefinition MakeExecutable (string name)
392                 {
393                         assembly = new AssemblyDefinition (this, name);
394                         return assembly;
395                 }
396                 
397                 public AssemblyDefinition MakeExecutable (string name, string fileName)
398                 {
399                         assembly = new AssemblyDefinition (this, name, fileName);
400                         return assembly;
401                 }
402
403                 //
404                 // Makes an initialized struct, returns the field builder that
405                 // references the data.  Thanks go to Sergey Chaban for researching
406                 // how to do this.  And coming up with a shorter mechanism than I
407                 // was able to figure out.
408                 //
409                 // This works but makes an implicit public struct $ArrayType$SIZE and
410                 // makes the fields point to it.  We could get more control if we did
411                 // use instead:
412                 //
413                 // 1. DefineNestedType on the impl_details_class with our struct.
414                 //
415                 // 2. Define the field on the impl_details_class
416                 //
417                 public FieldBuilder MakeStaticData (byte[] data)
418                 {
419                         if (TypeBuilder == null) {
420                                 TypeBuilder = builder.DefineType ("<PrivateImplementationDetails>",
421                                         TypeAttributes.NotPublic, TypeManager.object_type.GetMetaInfo ());
422                         }
423
424                         var fb = TypeBuilder.DefineInitializedData (
425                                 "$$field-" + (static_data_counter++), data,
426                                 FieldAttributes.Static | FieldAttributes.Assembly);
427
428                         return fb;
429                 }
430
431                 protected override bool AddMemberType (TypeContainer ds)
432                 {
433                         if (!AddToContainer (ds, ds.Name))
434                                 return false;
435                         ds.NamespaceEntry.NS.AddType (ds.Definition);
436                         return true;
437                 }
438
439                 protected override void RemoveMemberType (DeclSpace ds)
440                 {
441                         ds.NamespaceEntry.NS.RemoveDeclSpace (ds.Basename);
442                         base.RemoveMemberType (ds);
443                 }
444
445                 /// <summary>
446                 /// It is called very early therefore can resolve only predefined attributes
447                 /// </summary>
448                 void ResolveGlobalAttributes ()
449                 {
450                         if (OptAttributes == null)
451                                 return;
452
453                         if (!OptAttributes.CheckTargets ())
454                                 return;
455
456                         // FIXME: Define is wrong as the type may not exist yet
457                         var DefaultCharSet_attr = new PredefinedAttribute (this, "System.Runtime.InteropServices", "DefaultCharSetAttribute");
458                         DefaultCharSet_attr.Define ();
459                         Attribute a = ResolveModuleAttribute (DefaultCharSet_attr);
460                         if (a != null) {
461                                 has_default_charset = true;
462                                 DefaultCharSet = a.GetCharSetValue ();
463                                 switch (DefaultCharSet) {
464                                 case CharSet.Ansi:
465                                 case CharSet.None:
466                                         break;
467                                 case CharSet.Auto:
468                                         DefaultCharSetType = TypeAttributes.AutoClass;
469                                         break;
470                                 case CharSet.Unicode:
471                                         DefaultCharSetType = TypeAttributes.UnicodeClass;
472                                         break;
473                                 default:
474                                         Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid", 
475                                                 DefaultCharSet_attr.GetSignatureForError ());
476                                         break;
477                                 }
478                         }
479                 }
480
481                 public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
482                 {
483                         Attribute a = OptAttributes.Search ("assembly", a_type);
484                         if (a != null) {
485                                 a.Resolve ();
486                         }
487                         return a;
488                 }
489
490                 Attribute ResolveModuleAttribute (PredefinedAttribute a_type)
491                 {
492                         Attribute a = OptAttributes.Search ("module", a_type);
493                         if (a != null) {
494                                 a.Resolve ();
495                         }
496                         return a;
497                 }
498         }
499
500         class RootDeclSpace : TypeContainer {
501                 public RootDeclSpace (NamespaceEntry ns)
502                         : base (ns, null, MemberName.Null, null, 0)
503                 {
504                         PartialContainer = RootContext.ToplevelTypes;
505                 }
506
507                 public override AttributeTargets AttributeTargets {
508                         get { throw new InternalErrorException ("should not be called"); }
509                 }
510
511                 public override CompilerContext Compiler {
512                         get {
513                                 return PartialContainer.Compiler;
514                         }
515                 }
516
517                 public override string DocCommentHeader {
518                         get { throw new InternalErrorException ("should not be called"); }
519                 }
520
521                 public override void DefineType ()
522                 {
523                         throw new InternalErrorException ("should not be called");
524                 }
525
526                 public override ModuleContainer Module {
527                         get {
528                                 return PartialContainer.Module;
529                         }
530                 }
531
532                 public override bool IsClsComplianceRequired ()
533                 {
534                         return PartialContainer.IsClsComplianceRequired ();
535                 }
536
537                 public override FullNamedExpression LookupNamespaceAlias (string name)
538                 {
539                         return NamespaceEntry.LookupNamespaceAlias (name);
540                 }
541         }
542 }