ac0f0af86b4966361bced5d7e9386273232a552f
[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.Runtime.InteropServices;
16 using Mono.CompilerServices.SymbolWriter;
17
18 #if STATIC
19 using IKVM.Reflection;
20 using IKVM.Reflection.Emit;
21 #else
22 using System.Reflection;
23 using System.Reflection.Emit;
24 #endif
25
26 namespace Mono.CSharp
27 {
28         //
29         // Module (top-level type) container
30         //
31         public class ModuleContainer : TypeContainer
32         {
33 #if STATIC
34                 //
35                 // Compiler generated container for static data
36                 //
37                 sealed class StaticDataContainer : CompilerGeneratedClass
38                 {
39                         Dictionary<int, Struct> size_types;
40                         new int fields;
41
42                         public StaticDataContainer (ModuleContainer module)
43                                 : base (module, new MemberName ("<PrivateImplementationDetails>" + module.builder.ModuleVersionId.ToString ("B"), Location.Null), Modifiers.STATIC)
44                         {
45                                 size_types = new Dictionary<int, Struct> ();
46                         }
47
48                         public override void CloseType ()
49                         {
50                                 base.CloseType ();
51
52                                 foreach (var entry in size_types) {
53                                         entry.Value.CloseType ();
54                                 }
55                         }
56
57                         public FieldSpec DefineInitializedData (byte[] data, Location loc)
58                         {
59                                 Struct size_type;
60                                 if (!size_types.TryGetValue (data.Length, out size_type)) {
61                                         //
62                                         // Build common type for this data length. We cannot use
63                                         // DefineInitializedData because it creates public type,
64                                         // and its name is not unique among modules
65                                         //
66                                         size_type = new Struct (null, this, new MemberName ("$ArrayType=" + data.Length, Location), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, null);
67                                         size_type.CreateType ();
68                                         size_type.DefineType ();
69
70                                         size_types.Add (data.Length, size_type);
71
72                                         var pa = Module.PredefinedAttributes.StructLayout;
73                                         if (pa.Constructor != null || pa.ResolveConstructor (Location, TypeManager.short_type)) {
74                                                 var argsEncoded = new AttributeEncoder ();
75                                                 argsEncoded.Encode ((short) LayoutKind.Explicit);
76
77                                                 var field_size = pa.GetField ("Size", TypeManager.int32_type, Location);
78                                                 var pack = pa.GetField ("Pack", TypeManager.int32_type, Location);
79                                                 if (field_size != null) {
80                                                         argsEncoded.EncodeNamedArguments (
81                                                                 new[] { field_size, pack },
82                                                                 new[] { new IntConstant ((int) data.Length, Location), new IntConstant (1, Location) }
83                                                         );
84                                                 }
85
86                                                 pa.EmitAttribute (size_type.TypeBuilder, argsEncoded);
87                                         }
88                                 }
89
90                                 var name = "$field-" + fields.ToString ("X");
91                                 ++fields;
92                                 const Modifiers fmod = Modifiers.STATIC | Modifiers.INTERNAL;
93                                 var fbuilder = TypeBuilder.DefineField (name, size_type.CurrentType.GetMetaInfo (), ModifiersExtensions.FieldAttr (fmod) | FieldAttributes.HasFieldRVA);
94                                 fbuilder.__SetDataAndRVA (data);
95
96                                 return new FieldSpec (CurrentType, null, size_type.CurrentType, fbuilder, fmod);
97                         }
98                 }
99
100                 StaticDataContainer static_data;
101
102                 //
103                 // Makes const data field inside internal type container
104                 //
105                 public FieldSpec MakeStaticData (byte[] data, Location loc)
106                 {
107                         if (static_data == null) {
108                                 static_data = new StaticDataContainer (this);
109                                 static_data.CreateType ();
110                                 static_data.DefineType ();
111
112                                 AddCompilerGeneratedClass (static_data);
113                         }
114
115                         return static_data.DefineInitializedData (data, loc);
116                 }
117 #endif
118
119                 public CharSet? DefaultCharSet;
120                 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
121
122                 Dictionary<int, List<AnonymousTypeClass>> anonymous_types;
123                 Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> arrays;
124
125                 AssemblyDefinition assembly;
126                 readonly CompilerContext context;
127                 readonly RootNamespace global_ns;
128                 Dictionary<string, RootNamespace> alias_ns;
129
130                 ModuleBuilder builder;
131
132                 bool has_extenstion_method;
133
134                 PredefinedAttributes predefined_attributes;
135                 PredefinedTypes predefined_types;
136
137                 static readonly string[] attribute_targets = new string[] { "assembly", "module" };
138
139                 public ModuleContainer (CompilerContext context)
140                         : base (null, null, MemberName.Null, null, 0)
141                 {
142                         this.context = context;
143
144                         caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected);
145
146                         types = new List<TypeContainer> ();
147                         anonymous_types = new Dictionary<int, List<AnonymousTypeClass>> ();
148                         global_ns = new GlobalRootNamespace ();
149                         alias_ns = new Dictionary<string, RootNamespace> ();
150                         arrays = new Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ();
151                 }
152
153                 #region Properties
154
155                 public Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ArraysCache {
156                         get {
157                                 return arrays;
158                         }
159                 }
160
161                 public override AttributeTargets AttributeTargets {
162                         get {
163                                 return AttributeTargets.Assembly;
164                         }
165                 }
166
167                 public ModuleBuilder Builder {
168                         get {
169                                 return builder;
170                         }
171                 }
172
173                 public override CompilerContext Compiler {
174                         get {
175                                 return context;
176                         }
177                 }
178
179                 public override AssemblyDefinition DeclaringAssembly {
180                         get {
181                                 return assembly;
182                         }
183                 }
184
185                 public bool HasDefaultCharSet {
186                         get {
187                                 return DefaultCharSet.HasValue;
188                         }
189                 }
190
191                 public bool HasExtensionMethod {
192                         get {
193                                 return has_extenstion_method;
194                         }
195                         set {
196                                 has_extenstion_method = value;
197                         }
198                 }
199
200                 //
201                 // Returns module global:: namespace
202                 //
203                 public RootNamespace GlobalRootNamespace {
204                     get {
205                         return global_ns;
206                     }
207                 }
208
209                 public override ModuleContainer Module {
210                         get {
211                                 return this;
212                         }
213                 }
214
215                 internal PredefinedAttributes PredefinedAttributes {
216                         get {
217                                 return predefined_attributes;
218                         }
219                 }
220
221                 internal PredefinedTypes PredefinedTypes {
222                         get {
223                                 return predefined_types;
224                         }
225                 }
226
227                 public override string[] ValidAttributeTargets {
228                         get {
229                                 return attribute_targets;
230                         }
231                 }
232
233                 #endregion
234
235                 public override void Accept (StructuralVisitor visitor)
236                 {
237                         visitor.Visit (this);
238                 }
239
240                 public void AddAnonymousType (AnonymousTypeClass type)
241                 {
242                         List<AnonymousTypeClass> existing;
243                         if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing))
244                         if (existing == null) {
245                                 existing = new List<AnonymousTypeClass> ();
246                                 anonymous_types.Add (type.Parameters.Count, existing);
247                         }
248
249                         existing.Add (type);
250                 }
251
252                 public void AddAttributes (List<Attribute> attrs)
253                 {
254                         AddAttributes (attrs, this);
255                 }
256
257                 public void AddAttributes (List<Attribute> attrs, IMemberContext context)
258                 {
259                         foreach (Attribute a in attrs)
260                                 a.AttachTo (this, context);
261
262                         if (attributes == null) {
263                                 attributes = new Attributes (attrs);
264                                 return;
265                         }
266                         attributes.AddAttributes (attrs);
267                 }
268
269                 public override TypeContainer AddPartial (TypeContainer nextPart)
270                 {
271                         return AddPartial (nextPart, nextPart.Name);
272                 }
273
274                 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
275                 {
276                         if (a.Target == AttributeTargets.Assembly) {
277                                 assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
278                                 return;
279                         }
280
281                         if (a.Type == pa.DefaultCharset) {
282                                 switch (a.GetCharSetValue ()) {
283                                 case CharSet.Ansi:
284                                 case CharSet.None:
285                                         break;
286                                 case CharSet.Auto:
287                                         DefaultCharSet = CharSet.Auto;
288                                         DefaultCharSetType = TypeAttributes.AutoClass;
289                                         break;
290                                 case CharSet.Unicode:
291                                         DefaultCharSet = CharSet.Unicode;
292                                         DefaultCharSetType = TypeAttributes.UnicodeClass;
293                                         break;
294                                 default:
295                                         Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid",
296                                                 a.GetSignatureForError ());
297                                         break;
298                                 }
299                         } else if (a.Type == pa.CLSCompliant) {
300                                 Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
301                                 if (cls == null) {
302                                         Report.Warning (3012, 1, a.Location,
303                                                 "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
304                                 } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) {
305                                         Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ());
306                                         Report.Warning (3017, 1, a.Location,
307                                                 "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
308                                         return;
309                                 }
310                         }
311
312                         builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
313                 }
314
315                 public override void CloseType ()
316                 {
317                         foreach (TypeContainer tc in types) {
318                                 tc.CloseType ();
319                         }
320
321                         if (compiler_generated != null)
322                                 foreach (CompilerGeneratedClass c in compiler_generated)
323                                         c.CloseType ();
324                 }
325
326                 public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
327                 {
328                         return builder.DefineType (name, attr, null, typeSize);
329                 }
330
331                 //
332                 // Creates alias global namespace
333                 //
334                 public RootNamespace CreateRootNamespace (string alias)
335                 {
336                         if (alias == global_ns.Alias) {
337                                 NamespaceEntry.Error_GlobalNamespaceRedefined (Location.Null, Report);
338                                 return global_ns;
339                         }
340
341                         RootNamespace rn;
342                         if (!alias_ns.TryGetValue (alias, out rn)) {
343                                 rn = new RootNamespace (alias);
344                                 alias_ns.Add (alias, rn);
345                         }
346
347                         return rn;
348                 }
349
350                 public void Create (AssemblyDefinition assembly, ModuleBuilder moduleBuilder)
351                 {
352                         this.assembly = assembly;
353                         builder = moduleBuilder;
354                 }
355
356                 public new void CreateType ()
357                 {
358                         foreach (TypeContainer tc in types)
359                                 tc.CreateType ();
360                 }
361
362                 public new void Define ()
363                 {
364                         InitializePredefinedTypes ();
365
366                         foreach (TypeContainer tc in types)
367                                 tc.DefineType ();
368
369                         foreach (TypeContainer tc in types)
370                                 tc.ResolveTypeParameters ();
371
372                         foreach (TypeContainer tc in types) {
373                                 try {
374                                         tc.Define ();
375                                 } catch (Exception e) {
376                                         throw new InternalErrorException (tc, e);
377                                 }
378                         }
379                 }
380
381                 public override void Emit ()
382                 {
383                         if (OptAttributes != null)
384                                 OptAttributes.Emit ();
385
386                         if (Compiler.Settings.Unsafe) {
387                                 var pa = PredefinedAttributes.UnverifiableCode;
388                                 if (pa.IsDefined)
389                                         pa.EmitAttribute (builder);
390                         }
391
392                         foreach (var tc in types)
393                                 tc.DefineConstants ();
394
395                         foreach (TypeContainer tc in types)
396                                 tc.EmitType ();
397
398                         if (Compiler.Report.Errors > 0)
399                                 return;
400
401                         foreach (TypeContainer tc in types)
402                                 tc.VerifyMembers ();
403
404                         if (compiler_generated != null)
405                                 foreach (var c in compiler_generated)
406                                         c.EmitType ();
407                 }
408
409                 public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
410                 {
411                         List<AnonymousTypeClass> candidates;
412                         if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
413                                 return null;
414
415                         int i;
416                         foreach (AnonymousTypeClass at in candidates) {
417                                 for (i = 0; i < parameters.Count; ++i) {
418                                         if (!parameters [i].Equals (at.Parameters [i]))
419                                                 break;
420                                 }
421
422                                 if (i == parameters.Count)
423                                         return at;
424                         }
425
426                         return null;
427                 }
428
429                 public RootNamespace GetRootNamespace (string name)
430                 {
431                         RootNamespace rn;
432                         alias_ns.TryGetValue (name, out rn);
433                         return rn;
434                 }
435
436                 public override string GetSignatureForError ()
437                 {
438                         return "<module>";
439                 }
440
441                 public void InitializePredefinedTypes ()
442                 {
443                         predefined_attributes = new PredefinedAttributes (this);
444                         predefined_types = new PredefinedTypes (this);
445                 }
446
447                 public override bool IsClsComplianceRequired ()
448                 {
449                         return DeclaringAssembly.IsCLSCompliant;
450                 }
451
452                 protected override bool AddMemberType (TypeContainer ds)
453                 {
454                         if (!AddToContainer (ds, ds.Name))
455                                 return false;
456                         ds.NamespaceEntry.NS.AddType (ds.Definition);
457                         return true;
458                 }
459
460                 protected override void RemoveMemberType (DeclSpace ds)
461                 {
462                         ds.NamespaceEntry.NS.RemoveDeclSpace (ds.Basename);
463                         base.RemoveMemberType (ds);
464                 }
465
466                 public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
467                 {
468                         Attribute a = OptAttributes.Search ("assembly", a_type);
469                         if (a != null) {
470                                 a.Resolve ();
471                         }
472                         return a;
473                 }
474
475                 public void SetDeclaringAssembly (AssemblyDefinition assembly)
476                 {
477                         // TODO: This setter is quite ugly but I have not found a way around it yet
478                         this.assembly = assembly;
479                 }
480         }
481
482         class RootDeclSpace : TypeContainer {
483                 public RootDeclSpace (ModuleContainer module, NamespaceEntry ns)
484                         : base (ns, null, MemberName.Null, null, 0)
485                 {
486                         PartialContainer = module;
487                 }
488
489                 public override AttributeTargets AttributeTargets {
490                         get { throw new InternalErrorException ("should not be called"); }
491                 }
492
493                 public override CompilerContext Compiler {
494                         get {
495                                 return PartialContainer.Compiler;
496                         }
497                 }
498
499                 public override string DocCommentHeader {
500                         get { throw new InternalErrorException ("should not be called"); }
501                 }
502
503                 public override void DefineType ()
504                 {
505                         throw new InternalErrorException ("should not be called");
506                 }
507
508                 public override ModuleContainer Module {
509                         get {
510                                 return PartialContainer.Module;
511                         }
512                 }
513
514                 public override void Accept (StructuralVisitor visitor)
515                 {
516                         throw new InternalErrorException ("should not be called");
517                 }
518
519                 public override bool IsClsComplianceRequired ()
520                 {
521                         return PartialContainer.IsClsComplianceRequired ();
522                 }
523
524                 public override FullNamedExpression LookupNamespaceAlias (string name)
525                 {
526                         return NamespaceEntry.LookupNamespaceAlias (name);
527                 }
528         }
529 }