Merge pull request #194 from QuickJack/master
[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 // 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
19 #if STATIC
20 using IKVM.Reflection;
21 using IKVM.Reflection.Emit;
22 #else
23 using System.Reflection;
24 using System.Reflection.Emit;
25 #endif
26
27 namespace Mono.CSharp
28 {
29         //
30         // Module (top-level type) container
31         //
32         public sealed class ModuleContainer : TypeContainer
33         {
34 #if STATIC
35                 //
36                 // Compiler generated container for static data
37                 //
38                 sealed class StaticDataContainer : CompilerGeneratedClass
39                 {
40                         readonly Dictionary<int, Struct> size_types;
41                         new int fields;
42
43                         public StaticDataContainer (ModuleContainer module)
44                                 : base (module, new MemberName ("<PrivateImplementationDetails>" + module.builder.ModuleVersionId.ToString ("B"), Location.Null), Modifiers.STATIC)
45                         {
46                                 size_types = new Dictionary<int, Struct> ();
47                         }
48
49                         public override void CloseType ()
50                         {
51                                 base.CloseType ();
52
53                                 foreach (var entry in size_types) {
54                                         entry.Value.CloseType ();
55                                 }
56                         }
57
58                         public FieldSpec DefineInitializedData (byte[] data, Location loc)
59                         {
60                                 Struct size_type;
61                                 if (!size_types.TryGetValue (data.Length, out size_type)) {
62                                         //
63                                         // Build common type for this data length. We cannot use
64                                         // DefineInitializedData because it creates public type,
65                                         // and its name is not unique among modules
66                                         //
67                                         size_type = new Struct (null, this, new MemberName ("$ArrayType=" + data.Length, loc), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, null);
68                                         size_type.CreateType ();
69                                         size_type.DefineType ();
70
71                                         size_types.Add (data.Length, size_type);
72
73                                         // It has to work even if StructLayoutAttribute does not exist
74                                         size_type.TypeBuilder.__SetLayout (1, data.Length);
75                                 }
76
77                                 var name = "$field-" + fields.ToString ("X");
78                                 ++fields;
79                                 const Modifiers fmod = Modifiers.STATIC | Modifiers.INTERNAL;
80                                 var fbuilder = TypeBuilder.DefineField (name, size_type.CurrentType.GetMetaInfo (), ModifiersExtensions.FieldAttr (fmod) | FieldAttributes.HasFieldRVA);
81                                 fbuilder.__SetDataAndRVA (data);
82
83                                 return new FieldSpec (CurrentType, null, size_type.CurrentType, fbuilder, fmod);
84                         }
85                 }
86
87                 StaticDataContainer static_data;
88
89                 //
90                 // Makes const data field inside internal type container
91                 //
92                 public FieldSpec MakeStaticData (byte[] data, Location loc)
93                 {
94                         if (static_data == null) {
95                                 static_data = new StaticDataContainer (this);
96                                 static_data.CreateType ();
97                                 static_data.DefineType ();
98
99                                 AddCompilerGeneratedClass (static_data);
100                         }
101
102                         return static_data.DefineInitializedData (data, loc);
103                 }
104 #endif
105
106                 public CharSet? DefaultCharSet;
107                 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
108
109                 readonly Dictionary<int, List<AnonymousTypeClass>> anonymous_types;
110                 readonly Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> array_types;
111                 readonly Dictionary<TypeSpec, PointerContainer> pointer_types;
112                 readonly Dictionary<TypeSpec, ReferenceContainer> reference_types;
113                 readonly Dictionary<TypeSpec, MethodSpec> attrs_cache;
114
115                 // Used for unique namespaces/types during parsing
116                 Dictionary<MemberName, ITypesContainer> defined_type_containers;
117
118                 AssemblyDefinition assembly;
119                 readonly CompilerContext context;
120                 readonly RootNamespace global_ns;
121                 readonly Dictionary<string, RootNamespace> alias_ns;
122
123                 ModuleBuilder builder;
124
125                 bool has_extenstion_method;
126
127                 PredefinedAttributes predefined_attributes;
128                 PredefinedTypes predefined_types;
129                 PredefinedMembers predefined_members;
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                         array_types = new Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ();
145                         pointer_types = new Dictionary<TypeSpec, PointerContainer> ();
146                         reference_types = new Dictionary<TypeSpec, ReferenceContainer> ();
147                         attrs_cache = new Dictionary<TypeSpec, MethodSpec> ();
148
149                         defined_type_containers = new Dictionary<MemberName, ITypesContainer> ();
150                 }
151
152                 #region Properties
153
154                 internal Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ArrayTypesCache {
155                         get {
156                                 return array_types;
157                         }
158                 }
159
160                 //
161                 // Cache for parameter-less attributes
162                 //
163                 internal Dictionary<TypeSpec, MethodSpec> AttributeConstructorCache {
164                         get {
165                                 return attrs_cache;
166                         }
167                 }
168
169                 public override AttributeTargets AttributeTargets {
170                         get {
171                                 return AttributeTargets.Assembly;
172                         }
173                 }
174
175                 public ModuleBuilder Builder {
176                         get {
177                                 return builder;
178                         }
179                 }
180
181                 public override CompilerContext Compiler {
182                         get {
183                                 return context;
184                         }
185                 }
186
187                 public override AssemblyDefinition DeclaringAssembly {
188                         get {
189                                 return assembly;
190                         }
191                 }
192
193                 internal DocumentationBuilder DocumentationBuilder {
194                         get; set;
195                 }
196
197                 public Evaluator Evaluator {
198                         get; set;
199                 }
200
201                 public bool HasDefaultCharSet {
202                         get {
203                                 return DefaultCharSet.HasValue;
204                         }
205                 }
206
207                 public bool HasExtensionMethod {
208                         get {
209                                 return has_extenstion_method;
210                         }
211                         set {
212                                 has_extenstion_method = value;
213                         }
214                 }
215
216                 public bool HasTypesFullyDefined {
217                         get; set;
218                 }
219
220                 //
221                 // Returns module global:: namespace
222                 //
223                 public RootNamespace GlobalRootNamespace {
224                     get {
225                         return global_ns;
226                     }
227                 }
228
229                 public override ModuleContainer Module {
230                         get {
231                                 return this;
232                         }
233                 }
234
235                 internal Dictionary<TypeSpec, PointerContainer> PointerTypesCache {
236                         get {
237                                 return pointer_types;
238                         }
239                 }
240
241                 internal PredefinedAttributes PredefinedAttributes {
242                         get {
243                                 return predefined_attributes;
244                         }
245                 }
246
247                 internal PredefinedMembers PredefinedMembers {
248                         get {
249                                 return predefined_members;
250                         }
251                 }
252
253                 internal PredefinedTypes PredefinedTypes {
254                         get {
255                                 return predefined_types;
256                         }
257                 }
258
259                 internal Dictionary<TypeSpec, ReferenceContainer> ReferenceTypesCache {
260                         get {
261                                 return reference_types;
262                         }
263                 }
264
265                 public override string[] ValidAttributeTargets {
266                         get {
267                                 return attribute_targets;
268                         }
269                 }
270
271                 #endregion
272
273                 public override void Accept (StructuralVisitor visitor)
274                 {
275                         visitor.Visit (this);
276                 }
277
278                 public void AddAnonymousType (AnonymousTypeClass type)
279                 {
280                         List<AnonymousTypeClass> existing;
281                         if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing))
282                         if (existing == null) {
283                                 existing = new List<AnonymousTypeClass> ();
284                                 anonymous_types.Add (type.Parameters.Count, existing);
285                         }
286
287                         existing.Add (type);
288                 }
289
290                 public void AddAttribute (Attribute attr, IMemberContext context)
291                 {
292                         attr.AttachTo (this, context);
293
294                         if (attributes == null) {
295                                 attributes = new Attributes (attr);
296                                 return;
297                         }
298
299                         attributes.AddAttribute (attr);
300                 }
301
302                 public override TypeContainer AddPartial (TypeContainer nextPart)
303                 {
304                         return AddPartial (nextPart, nextPart.Name);
305                 }
306
307                 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
308                 {
309                         if (a.Target == AttributeTargets.Assembly) {
310                                 assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
311                                 return;
312                         }
313
314                         if (a.Type == pa.DefaultCharset) {
315                                 switch (a.GetCharSetValue ()) {
316                                 case CharSet.Ansi:
317                                 case CharSet.None:
318                                         break;
319                                 case CharSet.Auto:
320                                         DefaultCharSet = CharSet.Auto;
321                                         DefaultCharSetType = TypeAttributes.AutoClass;
322                                         break;
323                                 case CharSet.Unicode:
324                                         DefaultCharSet = CharSet.Unicode;
325                                         DefaultCharSetType = TypeAttributes.UnicodeClass;
326                                         break;
327                                 default:
328                                         Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid",
329                                                 a.GetSignatureForError ());
330                                         break;
331                                 }
332                         } else if (a.Type == pa.CLSCompliant) {
333                                 Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
334                                 if (cls == null) {
335                                         Report.Warning (3012, 1, a.Location,
336                                                 "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
337                                 } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) {
338                                         Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ());
339                                         Report.Warning (3017, 1, a.Location,
340                                                 "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
341                                         return;
342                                 }
343                         }
344
345                         builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
346                 }
347
348                 public override void CloseType ()
349                 {
350                         foreach (TypeContainer tc in types) {
351                                 tc.CloseType ();
352                         }
353
354                         if (compiler_generated != null)
355                                 foreach (CompilerGeneratedClass c in compiler_generated)
356                                         c.CloseType ();
357                 }
358
359                 public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
360                 {
361                         return builder.DefineType (name, attr, null, typeSize);
362                 }
363
364                 //
365                 // Creates alias global namespace
366                 //
367                 public RootNamespace CreateRootNamespace (string alias)
368                 {
369                         if (alias == global_ns.Alias) {
370                                 NamespaceContainer.Error_GlobalNamespaceRedefined (Location.Null, Report);
371                                 return global_ns;
372                         }
373
374                         RootNamespace rn;
375                         if (!alias_ns.TryGetValue (alias, out rn)) {
376                                 rn = new RootNamespace (alias);
377                                 alias_ns.Add (alias, rn);
378                         }
379
380                         return rn;
381                 }
382
383                 public void Create (AssemblyDefinition assembly, ModuleBuilder moduleBuilder)
384                 {
385                         this.assembly = assembly;
386                         builder = moduleBuilder;
387                 }
388
389                 public new void CreateType ()
390                 {
391                         // Release cache used by parser only
392                         if (Evaluator == null)
393                                 defined_type_containers = null;
394                         else
395                                 defined_type_containers.Clear ();
396
397                         foreach (TypeContainer tc in types)
398                                 tc.CreateType ();
399                 }
400
401                 public new void Define ()
402                 {
403                         foreach (TypeContainer tc in types) {
404                                 try {
405                                         tc.DefineType ();
406                                 } catch (Exception e) {
407                                         throw new InternalErrorException (tc, e);
408                                 }
409                         }
410
411                         foreach (TypeContainer tc in types)
412                                 tc.ResolveTypeParameters ();
413
414                         foreach (TypeContainer tc in types) {
415                                 try {
416                                         tc.Define ();
417                                 } catch (Exception e) {
418                                         throw new InternalErrorException (tc, e);
419                                 }
420                         }
421
422                         HasTypesFullyDefined = true;
423                 }
424
425                 public override void Emit ()
426                 {
427                         if (OptAttributes != null)
428                                 OptAttributes.Emit ();
429
430                         if (Compiler.Settings.Unsafe) {
431                                 var pa = PredefinedAttributes.UnverifiableCode;
432                                 if (pa.IsDefined)
433                                         pa.EmitAttribute (builder);
434                         }
435
436                         foreach (var tc in types)
437                                 tc.DefineConstants ();
438
439                         foreach (TypeContainer tc in types)
440                                 tc.EmitType ();
441
442                         if (Compiler.Report.Errors > 0)
443                                 return;
444
445                         foreach (TypeContainer tc in types)
446                                 tc.VerifyMembers ();
447
448                         if (compiler_generated != null)
449                                 foreach (var c in compiler_generated)
450                                         c.EmitType ();
451                 }
452
453                 internal override void GenerateDocComment (DocumentationBuilder builder)
454                 {
455                         foreach (var tc in types)
456                                 tc.GenerateDocComment (builder);
457                 }
458
459                 public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
460                 {
461                         List<AnonymousTypeClass> candidates;
462                         if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
463                                 return null;
464
465                         int i;
466                         foreach (AnonymousTypeClass at in candidates) {
467                                 for (i = 0; i < parameters.Count; ++i) {
468                                         if (!parameters [i].Equals (at.Parameters [i]))
469                                                 break;
470                                 }
471
472                                 if (i == parameters.Count)
473                                         return at;
474                         }
475
476                         return null;
477                 }
478
479                 public RootNamespace GetRootNamespace (string name)
480                 {
481                         RootNamespace rn;
482                         alias_ns.TryGetValue (name, out rn);
483                         return rn;
484                 }
485
486                 public override string GetSignatureForError ()
487                 {
488                         return "<module>";
489                 }
490
491                 public void InitializePredefinedTypes ()
492                 {
493                         predefined_attributes = new PredefinedAttributes (this);
494                         predefined_types = new PredefinedTypes (this);
495                         predefined_members = new PredefinedMembers (this);
496                 }
497
498                 public override bool IsClsComplianceRequired ()
499                 {
500                         return DeclaringAssembly.IsCLSCompliant;
501                 }
502
503                 protected override bool AddMemberType (TypeContainer tc)
504                 {
505                         if (AddTypesContainer (tc)) {
506                                 if ((tc.ModFlags & Modifiers.PARTIAL) != 0)
507                                         defined_names.Add (tc.Name, tc);
508
509                                 tc.NamespaceEntry.NS.AddType (this, tc.Definition);
510                                 return true;
511                         }
512
513                         return false;
514                 }
515
516                 public bool AddTypesContainer (ITypesContainer container)
517                 {
518                         var mn = container.MemberName;
519                         ITypesContainer found;
520                         if (!defined_type_containers.TryGetValue (mn, out found)) {
521                                 defined_type_containers.Add (mn, container);
522                                 return true;
523                         }
524
525                         if (container is NamespaceContainer && found is NamespaceContainer)
526                                 return true;
527
528                         var container_tc = container as TypeContainer;
529                         var found_tc = found as TypeContainer;
530                         if (container_tc != null && found_tc != null && container_tc.Kind == found_tc.Kind) {
531                                 if ((found_tc.ModFlags & container_tc.ModFlags & Modifiers.PARTIAL) != 0) {
532                                         return false;
533                                 }
534
535                                 if (((found_tc.ModFlags | container_tc.ModFlags) & Modifiers.PARTIAL) != 0) {
536                                         Report.SymbolRelatedToPreviousError (found_tc);
537                                         Error_MissingPartialModifier (container_tc);
538                                         return false;
539                                 }
540                         }
541
542                         string ns = mn.Left != null ? mn.Left.GetSignatureForError () : Module.GlobalRootNamespace.GetSignatureForError ();
543                         mn = new MemberName (mn.Name, mn.TypeArguments, mn.Location);
544
545                         Report.SymbolRelatedToPreviousError (found.Location, "");
546                         Report.Error (101, container.Location,
547                                 "The namespace `{0}' already contains a definition for `{1}'",
548                                 ns, mn.GetSignatureForError ());
549                         return false;
550                 }
551
552                 protected override void RemoveMemberType (TypeContainer ds)
553                 {
554                         defined_type_containers.Remove (ds.MemberName);
555                         ds.NamespaceEntry.NS.RemoveDeclSpace (ds.Basename);
556                         base.RemoveMemberType (ds);
557                 }
558
559                 public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
560                 {
561                         Attribute a = OptAttributes.Search ("assembly", a_type);
562                         if (a != null) {
563                                 a.Resolve ();
564                         }
565                         return a;
566                 }
567
568                 public void SetDeclaringAssembly (AssemblyDefinition assembly)
569                 {
570                         // TODO: This setter is quite ugly but I have not found a way around it yet
571                         this.assembly = assembly;
572                 }
573         }
574
575         sealed class RootDeclSpace : TypeContainer {
576                 public RootDeclSpace (ModuleContainer module, NamespaceContainer ns)
577                         : base (ns, null, MemberName.Null, null, 0)
578                 {
579                         PartialContainer = module;
580                 }
581
582                 public override AttributeTargets AttributeTargets {
583                         get { throw new InternalErrorException ("should not be called"); }
584                 }
585
586                 public override CompilerContext Compiler {
587                         get {
588                                 return PartialContainer.Compiler;
589                         }
590                 }
591
592                 public override string DocCommentHeader {
593                         get { throw new InternalErrorException ("should not be called"); }
594                 }
595
596                 public override void DefineType ()
597                 {
598                         throw new InternalErrorException ("should not be called");
599                 }
600
601                 public override ModuleContainer Module {
602                         get {
603                                 return PartialContainer.Module;
604                         }
605                 }
606
607                 public override void Accept (StructuralVisitor visitor)
608                 {
609                         throw new InternalErrorException ("should not be called");
610                 }
611
612                 public override bool IsClsComplianceRequired ()
613                 {
614                         return PartialContainer.IsClsComplianceRequired ();
615                 }
616
617                 public override ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
618                 {
619                         return null;
620                 }
621
622                 public override FullNamedExpression LookupNamespaceAlias (string name)
623                 {
624                         return NamespaceEntry.LookupNamespaceAlias (name);
625                 }
626         }
627 }