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