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