Merge pull request #733 from amoiseev-softheme/bugfix/monofix
[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 : CompilerGeneratedContainer
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),
46                                         Modifiers.STATIC | Modifiers.INTERNAL)
47                         {
48                                 size_types = new Dictionary<int, Struct> ();
49                         }
50
51                         public override void CloseContainer ()
52                         {
53                                 base.CloseContainer ();
54
55                                 foreach (var entry in size_types) {
56                                         entry.Value.CloseContainer ();
57                                 }
58                         }
59
60                         public FieldSpec DefineInitializedData (byte[] data, Location loc)
61                         {
62                                 Struct size_type;
63                                 if (!size_types.TryGetValue (data.Length, out size_type)) {
64                                         //
65                                         // Build common type for this data length. We cannot use
66                                         // DefineInitializedData because it creates public type,
67                                         // and its name is not unique among modules
68                                         //
69                                         size_type = new Struct (this, new MemberName ("$ArrayType=" + data.Length, loc), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, null);
70                                         size_type.CreateContainer ();
71                                         size_type.DefineContainer ();
72
73                                         size_types.Add (data.Length, size_type);
74
75                                         // It has to work even if StructLayoutAttribute does not exist
76                                         size_type.TypeBuilder.__SetLayout (1, data.Length);
77                                 }
78
79                                 var name = "$field-" + fields.ToString ("X");
80                                 ++fields;
81                                 const Modifiers fmod = Modifiers.STATIC | Modifiers.INTERNAL;
82                                 var fbuilder = TypeBuilder.DefineField (name, size_type.CurrentType.GetMetaInfo (), ModifiersExtensions.FieldAttr (fmod) | FieldAttributes.HasFieldRVA);
83                                 fbuilder.__SetDataAndRVA (data);
84
85                                 return new FieldSpec (CurrentType, null, size_type.CurrentType, fbuilder, fmod);
86                         }
87                 }
88
89                 StaticDataContainer static_data;
90
91                 //
92                 // Makes const data field inside internal type container
93                 //
94                 public FieldSpec MakeStaticData (byte[] data, Location loc)
95                 {
96                         if (static_data == null) {
97                                 static_data = new StaticDataContainer (this);
98                                 static_data.CreateContainer ();
99                                 static_data.DefineContainer ();
100
101                                 AddCompilerGeneratedClass (static_data);
102                         }
103
104                         return static_data.DefineInitializedData (data, loc);
105                 }
106 #endif
107
108                 public CharSet? DefaultCharSet;
109                 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
110
111                 readonly Dictionary<int, List<AnonymousTypeClass>> anonymous_types;
112                 readonly Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> array_types;
113                 readonly Dictionary<TypeSpec, PointerContainer> pointer_types;
114                 readonly Dictionary<TypeSpec, ReferenceContainer> reference_types;
115                 readonly Dictionary<TypeSpec, MethodSpec> attrs_cache;
116                 readonly Dictionary<TypeSpec, AwaiterDefinition> awaiters;
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                 public Binary.PredefinedOperator[] OperatorsBinaryEqualityLifted;
132                 public Binary.PredefinedOperator[] OperatorsBinaryLifted;
133
134                 static readonly string[] attribute_targets = new string[] { "assembly", "module" };
135
136                 public ModuleContainer (CompilerContext context)
137                         : base (null, MemberName.Null, null, 0)
138                 {
139                         this.context = context;
140
141                         caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected);
142
143                         containers = new List<TypeContainer> ();
144                         anonymous_types = new Dictionary<int, List<AnonymousTypeClass>> ();
145                         global_ns = new GlobalRootNamespace ();
146                         alias_ns = new Dictionary<string, RootNamespace> ();
147                         array_types = new Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ();
148                         pointer_types = new Dictionary<TypeSpec, PointerContainer> ();
149                         reference_types = new Dictionary<TypeSpec, ReferenceContainer> ();
150                         attrs_cache = new Dictionary<TypeSpec, MethodSpec> ();
151                         awaiters = new Dictionary<TypeSpec, AwaiterDefinition> ();
152                 }
153
154                 #region Properties
155
156                 internal Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ArrayTypesCache {
157                         get {
158                                 return array_types;
159                         }
160                 }
161
162                 //
163                 // Cache for parameter-less attributes
164                 //
165                 internal Dictionary<TypeSpec, MethodSpec> AttributeConstructorCache {
166                         get {
167                                 return attrs_cache;
168                         }
169                 }
170
171                 public override AttributeTargets AttributeTargets {
172                         get {
173                                 return AttributeTargets.Assembly;
174                         }
175                 }
176
177                 public ModuleBuilder Builder {
178                         get {
179                                 return builder;
180                         }
181                 }
182
183                 public override CompilerContext Compiler {
184                         get {
185                                 return context;
186                         }
187                 }
188
189                 public int CounterAnonymousTypes { get; set; }
190                 public int CounterAnonymousMethods { get; set; }
191                 public int CounterAnonymousContainers { get; set; }
192                 public int CounterSwitchTypes { get; set; }
193
194                 public AssemblyDefinition DeclaringAssembly {
195                         get {
196                                 return assembly;
197                         }
198                 }
199
200                 internal DocumentationBuilder DocumentationBuilder {
201                         get; set;
202                 }
203
204                 public override string DocCommentHeader {
205                         get {
206                                 throw new NotSupportedException ();
207                         }
208                 }
209
210                 public Evaluator Evaluator {
211                         get; set;
212                 }
213
214                 public bool HasDefaultCharSet {
215                         get {
216                                 return DefaultCharSet.HasValue;
217                         }
218                 }
219
220                 public bool HasExtensionMethod {
221                         get {
222                                 return has_extenstion_method;
223                         }
224                         set {
225                                 has_extenstion_method = value;
226                         }
227                 }
228
229                 public bool HasTypesFullyDefined {
230                         get; set;
231                 }
232
233                 //
234                 // Returns module global:: namespace
235                 //
236                 public RootNamespace GlobalRootNamespace {
237                     get {
238                         return global_ns;
239                     }
240                 }
241
242                 public override ModuleContainer Module {
243                         get {
244                                 return this;
245                         }
246                 }
247
248                 internal Dictionary<TypeSpec, PointerContainer> PointerTypesCache {
249                         get {
250                                 return pointer_types;
251                         }
252                 }
253
254                 internal PredefinedAttributes PredefinedAttributes {
255                         get {
256                                 return predefined_attributes;
257                         }
258                 }
259
260                 internal PredefinedMembers PredefinedMembers {
261                         get {
262                                 return predefined_members;
263                         }
264                 }
265
266                 internal PredefinedTypes PredefinedTypes {
267                         get {
268                                 return predefined_types;
269                         }
270                 }
271
272                 internal Dictionary<TypeSpec, ReferenceContainer> ReferenceTypesCache {
273                         get {
274                                 return reference_types;
275                         }
276                 }
277
278                 public override string[] ValidAttributeTargets {
279                         get {
280                                 return attribute_targets;
281                         }
282                 }
283
284                 #endregion
285
286                 public override void Accept (StructuralVisitor visitor)
287                 {
288                         visitor.Visit (this);
289                 }
290
291                 public void AddAnonymousType (AnonymousTypeClass type)
292                 {
293                         List<AnonymousTypeClass> existing;
294                         if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing))
295                         if (existing == null) {
296                                 existing = new List<AnonymousTypeClass> ();
297                                 anonymous_types.Add (type.Parameters.Count, existing);
298                         }
299
300                         existing.Add (type);
301                 }
302
303                 public void AddAttribute (Attribute attr, IMemberContext context)
304                 {
305                         attr.AttachTo (this, context);
306
307                         if (attributes == null) {
308                                 attributes = new Attributes (attr);
309                                 return;
310                         }
311
312                         attributes.AddAttribute (attr);
313                 }
314
315                 public override void AddTypeContainer (TypeContainer tc)
316                 {
317                         AddTypeContainerMember (tc);
318                 }
319
320                 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
321                 {
322                         if (a.Target == AttributeTargets.Assembly) {
323                                 assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
324                                 return;
325                         }
326
327                         if (a.Type == pa.DefaultCharset) {
328                                 switch (a.GetCharSetValue ()) {
329                                 case CharSet.Ansi:
330                                 case CharSet.None:
331                                         break;
332                                 case CharSet.Auto:
333                                         DefaultCharSet = CharSet.Auto;
334                                         DefaultCharSetType = TypeAttributes.AutoClass;
335                                         break;
336                                 case CharSet.Unicode:
337                                         DefaultCharSet = CharSet.Unicode;
338                                         DefaultCharSetType = TypeAttributes.UnicodeClass;
339                                         break;
340                                 default:
341                                         Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid",
342                                                 a.GetSignatureForError ());
343                                         break;
344                                 }
345                         } else if (a.Type == pa.CLSCompliant) {
346                                 Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
347                                 if (cls == null) {
348                                         Report.Warning (3012, 1, a.Location,
349                                                 "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
350                                 } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) {
351                                         Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ());
352                                         Report.Warning (3017, 1, a.Location,
353                                                 "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
354                                         return;
355                                 }
356                         }
357
358                         builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
359                 }
360
361                 public override void CloseContainer ()
362                 {
363                         if (anonymous_types != null) {
364                                 foreach (var atypes in anonymous_types)
365                                         foreach (var at in atypes.Value)
366                                                 at.CloseContainer ();
367                         }
368
369                         base.CloseContainer ();
370                 }
371
372                 public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
373                 {
374                         return builder.DefineType (name, attr, null, typeSize);
375                 }
376
377                 //
378                 // Creates alias global namespace
379                 //
380                 public RootNamespace CreateRootNamespace (string alias)
381                 {
382                         if (alias == global_ns.Alias) {
383                                 RootNamespace.Error_GlobalNamespaceRedefined (Report, Location.Null);
384                                 return global_ns;
385                         }
386
387                         RootNamespace rn;
388                         if (!alias_ns.TryGetValue (alias, out rn)) {
389                                 rn = new RootNamespace (alias);
390                                 alias_ns.Add (alias, rn);
391                         }
392
393                         return rn;
394                 }
395
396                 public void Create (AssemblyDefinition assembly, ModuleBuilder moduleBuilder)
397                 {
398                         this.assembly = assembly;
399                         builder = moduleBuilder;
400                 }
401
402                 public override bool Define ()
403                 {
404                         DefineContainer ();
405
406                         ExpandBaseInterfaces ();
407
408                         base.Define ();
409
410                         HasTypesFullyDefined = true;
411
412                         return true;
413                 }
414
415                 public override bool DefineContainer ()
416                 {
417                         DefineNamespace ();
418
419                         return base.DefineContainer ();
420                 }
421
422                 public void EnableRedefinition ()
423                 {
424                         is_defined = false;
425                 }
426
427                 public override void EmitContainer ()
428                 {
429                         if (OptAttributes != null)
430                                 OptAttributes.Emit ();
431
432                         if (Compiler.Settings.Unsafe && !assembly.IsSatelliteAssembly) {
433                                 var pa = PredefinedAttributes.UnverifiableCode;
434                                 if (pa.IsDefined)
435                                         pa.EmitAttribute (builder);
436                         }
437
438                         foreach (var tc in containers) {
439                                 tc.PrepareEmit ();
440                         }
441
442                         base.EmitContainer ();
443
444                         if (Compiler.Report.Errors == 0 && !Compiler.Settings.WriteMetadataOnly)
445                                 VerifyMembers ();
446
447                         if (anonymous_types != null) {
448                                 foreach (var atypes in anonymous_types)
449                                         foreach (var at in atypes.Value)
450                                                 at.EmitContainer ();
451                         }
452                 }
453
454                 internal override void GenerateDocComment (DocumentationBuilder builder)
455                 {
456                         foreach (var tc in containers)
457                                 tc.GenerateDocComment (builder);
458                 }
459
460                 public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
461                 {
462                         List<AnonymousTypeClass> candidates;
463                         if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
464                                 return null;
465
466                         int i;
467                         foreach (AnonymousTypeClass at in candidates) {
468                                 for (i = 0; i < parameters.Count; ++i) {
469                                         if (!parameters [i].Equals (at.Parameters [i]))
470                                                 break;
471                                 }
472
473                                 if (i == parameters.Count)
474                                         return at;
475                         }
476
477                         return null;
478                 }
479
480                 //
481                 // Return container with awaiter definition. It never returns null
482                 // but all container member can be null for easier error reporting
483                 //
484                 public AwaiterDefinition GetAwaiter (TypeSpec type)
485                 {
486                         AwaiterDefinition awaiter;
487                         if (awaiters.TryGetValue (type, out awaiter))
488                                 return awaiter;
489
490                         awaiter = new AwaiterDefinition ();
491
492                         //
493                         // Predefined: bool IsCompleted { get; } 
494                         //
495                         awaiter.IsCompleted = MemberCache.FindMember (type, MemberFilter.Property ("IsCompleted", Compiler.BuiltinTypes.Bool),
496                                 BindingRestriction.InstanceOnly) as PropertySpec;
497
498                         //
499                         // Predefined: GetResult ()
500                         //
501                         // The method return type is also result type of await expression
502                         //
503                         awaiter.GetResult = MemberCache.FindMember (type, MemberFilter.Method ("GetResult", 0,
504                                 ParametersCompiled.EmptyReadOnlyParameters, null),
505                                 BindingRestriction.InstanceOnly) as MethodSpec;
506
507                         //
508                         // Predefined: INotifyCompletion.OnCompleted (System.Action)
509                         //
510                         var nc = PredefinedTypes.INotifyCompletion;
511                         awaiter.INotifyCompletion = !nc.Define () || type.ImplementsInterface (nc.TypeSpec, false);
512
513                         awaiters.Add (type, awaiter);
514                         return awaiter;
515                 }
516
517                 public override void GetCompletionStartingWith (string prefix, List<string> results)
518                 {
519                         var names = Evaluator.GetVarNames ();
520                         results.AddRange (names.Where (l => l.StartsWith (prefix)));
521                 }
522
523                 public RootNamespace GetRootNamespace (string name)
524                 {
525                         RootNamespace rn;
526                         alias_ns.TryGetValue (name, out rn);
527                         return rn;
528                 }
529
530                 public override string GetSignatureForError ()
531                 {
532                         return "<module>";
533                 }
534
535                 public Binary.PredefinedOperator[] GetPredefinedEnumAritmeticOperators (TypeSpec enumType, bool nullable)
536                 {
537                         TypeSpec underlying;
538                         Binary.Operator mask = 0;
539
540                         if (nullable) {
541                                 underlying = Nullable.NullableInfo.GetEnumUnderlyingType (this, enumType);
542                                 mask = Binary.Operator.NullableMask;
543                         } else {
544                                 underlying = EnumSpec.GetUnderlyingType (enumType);
545                         }
546
547                         var operators = new[] {
548                                 new Binary.PredefinedOperator (enumType, underlying,
549                                         mask | Binary.Operator.AdditionMask | Binary.Operator.SubtractionMask | Binary.Operator.DecomposedMask, enumType),
550                                 new Binary.PredefinedOperator (underlying, enumType,
551                                         mask | Binary.Operator.AdditionMask | Binary.Operator.SubtractionMask | Binary.Operator.DecomposedMask, enumType),
552                                 new Binary.PredefinedOperator (enumType, mask | Binary.Operator.SubtractionMask, underlying)
553                         };
554
555                         return operators;
556                 }
557
558                 public void InitializePredefinedTypes ()
559                 {
560                         predefined_attributes = new PredefinedAttributes (this);
561                         predefined_types = new PredefinedTypes (this);
562                         predefined_members = new PredefinedMembers (this);
563
564                         OperatorsBinaryEqualityLifted = Binary.CreateEqualityLiftedOperatorsTable (this);
565                         OperatorsBinaryLifted = Binary.CreateStandardLiftedOperatorsTable (this);
566                 }
567
568                 public override bool IsClsComplianceRequired ()
569                 {
570                         return DeclaringAssembly.IsCLSCompliant;
571                 }
572
573                 public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
574                 {
575                         Attribute a = OptAttributes.Search ("assembly", a_type);
576                         if (a != null) {
577                                 a.Resolve ();
578                         }
579                         return a;
580                 }
581
582                 public void SetDeclaringAssembly (AssemblyDefinition assembly)
583                 {
584                         // TODO: This setter is quite ugly but I have not found a way around it yet
585                         this.assembly = assembly;
586                 }
587         }
588 }