[System.Net] Add support for .pac proxy config scripts on mac
[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
191                 public AssemblyDefinition DeclaringAssembly {
192                         get {
193                                 return assembly;
194                         }
195                 }
196
197                 internal DocumentationBuilder DocumentationBuilder {
198                         get; set;
199                 }
200
201                 public override string DocCommentHeader {
202                         get {
203                                 throw new NotSupportedException ();
204                         }
205                 }
206
207                 public Evaluator Evaluator {
208                         get; set;
209                 }
210
211                 public bool HasDefaultCharSet {
212                         get {
213                                 return DefaultCharSet.HasValue;
214                         }
215                 }
216
217                 public bool HasExtensionMethod {
218                         get {
219                                 return has_extenstion_method;
220                         }
221                         set {
222                                 has_extenstion_method = value;
223                         }
224                 }
225
226                 public bool HasTypesFullyDefined {
227                         get; set;
228                 }
229
230                 //
231                 // Returns module global:: namespace
232                 //
233                 public RootNamespace GlobalRootNamespace {
234                     get {
235                         return global_ns;
236                     }
237                 }
238
239                 public override ModuleContainer Module {
240                         get {
241                                 return this;
242                         }
243                 }
244
245                 internal Dictionary<TypeSpec, PointerContainer> PointerTypesCache {
246                         get {
247                                 return pointer_types;
248                         }
249                 }
250
251                 internal PredefinedAttributes PredefinedAttributes {
252                         get {
253                                 return predefined_attributes;
254                         }
255                 }
256
257                 internal PredefinedMembers PredefinedMembers {
258                         get {
259                                 return predefined_members;
260                         }
261                 }
262
263                 internal PredefinedTypes PredefinedTypes {
264                         get {
265                                 return predefined_types;
266                         }
267                 }
268
269                 internal Dictionary<TypeSpec, ReferenceContainer> ReferenceTypesCache {
270                         get {
271                                 return reference_types;
272                         }
273                 }
274
275                 public override string[] ValidAttributeTargets {
276                         get {
277                                 return attribute_targets;
278                         }
279                 }
280
281                 #endregion
282
283                 public override void Accept (StructuralVisitor visitor)
284                 {
285                         visitor.Visit (this);
286                 }
287
288                 public void AddAnonymousType (AnonymousTypeClass type)
289                 {
290                         List<AnonymousTypeClass> existing;
291                         if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing))
292                         if (existing == null) {
293                                 existing = new List<AnonymousTypeClass> ();
294                                 anonymous_types.Add (type.Parameters.Count, existing);
295                         }
296
297                         existing.Add (type);
298                 }
299
300                 public void AddAttribute (Attribute attr, IMemberContext context)
301                 {
302                         attr.AttachTo (this, context);
303
304                         if (attributes == null) {
305                                 attributes = new Attributes (attr);
306                                 return;
307                         }
308
309                         attributes.AddAttribute (attr);
310                 }
311
312                 public override void AddTypeContainer (TypeContainer tc)
313                 {
314                         AddTypeContainerMember (tc);
315                 }
316
317                 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
318                 {
319                         if (a.Target == AttributeTargets.Assembly) {
320                                 assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
321                                 return;
322                         }
323
324                         if (a.Type == pa.DefaultCharset) {
325                                 switch (a.GetCharSetValue ()) {
326                                 case CharSet.Ansi:
327                                 case CharSet.None:
328                                         break;
329                                 case CharSet.Auto:
330                                         DefaultCharSet = CharSet.Auto;
331                                         DefaultCharSetType = TypeAttributes.AutoClass;
332                                         break;
333                                 case CharSet.Unicode:
334                                         DefaultCharSet = CharSet.Unicode;
335                                         DefaultCharSetType = TypeAttributes.UnicodeClass;
336                                         break;
337                                 default:
338                                         Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid",
339                                                 a.GetSignatureForError ());
340                                         break;
341                                 }
342                         } else if (a.Type == pa.CLSCompliant) {
343                                 Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
344                                 if (cls == null) {
345                                         Report.Warning (3012, 1, a.Location,
346                                                 "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
347                                 } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) {
348                                         Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ());
349                                         Report.Warning (3017, 1, a.Location,
350                                                 "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
351                                         return;
352                                 }
353                         }
354
355                         builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
356                 }
357
358                 public override void CloseContainer ()
359                 {
360                         if (anonymous_types != null) {
361                                 foreach (var atypes in anonymous_types)
362                                         foreach (var at in atypes.Value)
363                                                 at.CloseContainer ();
364                         }
365
366                         base.CloseContainer ();
367                 }
368
369                 public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
370                 {
371                         return builder.DefineType (name, attr, null, typeSize);
372                 }
373
374                 //
375                 // Creates alias global namespace
376                 //
377                 public RootNamespace CreateRootNamespace (string alias)
378                 {
379                         if (alias == global_ns.Alias) {
380                                 RootNamespace.Error_GlobalNamespaceRedefined (Report, Location.Null);
381                                 return global_ns;
382                         }
383
384                         RootNamespace rn;
385                         if (!alias_ns.TryGetValue (alias, out rn)) {
386                                 rn = new RootNamespace (alias);
387                                 alias_ns.Add (alias, rn);
388                         }
389
390                         return rn;
391                 }
392
393                 public void Create (AssemblyDefinition assembly, ModuleBuilder moduleBuilder)
394                 {
395                         this.assembly = assembly;
396                         builder = moduleBuilder;
397                 }
398
399                 public override bool Define ()
400                 {
401                         DefineContainer ();
402
403                         ExpandBaseInterfaces ();
404
405                         base.Define ();
406
407                         HasTypesFullyDefined = true;
408
409                         return true;
410                 }
411
412                 public override bool DefineContainer ()
413                 {
414                         DefineNamespace ();
415
416                         return base.DefineContainer ();
417                 }
418
419                 public void EnableRedefinition ()
420                 {
421                         is_defined = false;
422                 }
423
424                 public override void EmitContainer ()
425                 {
426                         if (OptAttributes != null)
427                                 OptAttributes.Emit ();
428
429                         if (Compiler.Settings.Unsafe && !assembly.IsSatelliteAssembly) {
430                                 var pa = PredefinedAttributes.UnverifiableCode;
431                                 if (pa.IsDefined)
432                                         pa.EmitAttribute (builder);
433                         }
434
435                         foreach (var tc in containers) {
436                                 tc.PrepareEmit ();
437                         }
438
439                         base.EmitContainer ();
440
441                         if (Compiler.Report.Errors == 0 && !Compiler.Settings.WriteMetadataOnly)
442                                 VerifyMembers ();
443
444                         if (anonymous_types != null) {
445                                 foreach (var atypes in anonymous_types)
446                                         foreach (var at in atypes.Value)
447                                                 at.EmitContainer ();
448                         }
449                 }
450
451                 internal override void GenerateDocComment (DocumentationBuilder builder)
452                 {
453                         foreach (var tc in containers)
454                                 tc.GenerateDocComment (builder);
455                 }
456
457                 public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
458                 {
459                         List<AnonymousTypeClass> candidates;
460                         if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
461                                 return null;
462
463                         int i;
464                         foreach (AnonymousTypeClass at in candidates) {
465                                 for (i = 0; i < parameters.Count; ++i) {
466                                         if (!parameters [i].Equals (at.Parameters [i]))
467                                                 break;
468                                 }
469
470                                 if (i == parameters.Count)
471                                         return at;
472                         }
473
474                         return null;
475                 }
476
477                 //
478                 // Return container with awaiter definition. It never returns null
479                 // but all container member can be null for easier error reporting
480                 //
481                 public AwaiterDefinition GetAwaiter (TypeSpec type)
482                 {
483                         AwaiterDefinition awaiter;
484                         if (awaiters.TryGetValue (type, out awaiter))
485                                 return awaiter;
486
487                         awaiter = new AwaiterDefinition ();
488
489                         //
490                         // Predefined: bool IsCompleted { get; } 
491                         //
492                         awaiter.IsCompleted = MemberCache.FindMember (type, MemberFilter.Property ("IsCompleted", Compiler.BuiltinTypes.Bool),
493                                 BindingRestriction.InstanceOnly) as PropertySpec;
494
495                         //
496                         // Predefined: GetResult ()
497                         //
498                         // The method return type is also result type of await expression
499                         //
500                         awaiter.GetResult = MemberCache.FindMember (type, MemberFilter.Method ("GetResult", 0,
501                                 ParametersCompiled.EmptyReadOnlyParameters, null),
502                                 BindingRestriction.InstanceOnly) as MethodSpec;
503
504                         //
505                         // Predefined: INotifyCompletion.OnCompleted (System.Action)
506                         //
507                         var nc = PredefinedTypes.INotifyCompletion;
508                         awaiter.INotifyCompletion = !nc.Define () || type.ImplementsInterface (nc.TypeSpec, false);
509
510                         awaiters.Add (type, awaiter);
511                         return awaiter;
512                 }
513
514                 public override void GetCompletionStartingWith (string prefix, List<string> results)
515                 {
516                         var names = Evaluator.GetVarNames ();
517                         results.AddRange (names.Where (l => l.StartsWith (prefix)));
518                 }
519
520                 public RootNamespace GetRootNamespace (string name)
521                 {
522                         RootNamespace rn;
523                         alias_ns.TryGetValue (name, out rn);
524                         return rn;
525                 }
526
527                 public override string GetSignatureForError ()
528                 {
529                         return "<module>";
530                 }
531
532                 public Binary.PredefinedOperator[] GetPredefinedEnumAritmeticOperators (TypeSpec enumType, bool nullable)
533                 {
534                         TypeSpec underlying;
535                         Binary.Operator mask = 0;
536
537                         if (nullable) {
538                                 underlying = Nullable.NullableInfo.GetEnumUnderlyingType (this, enumType);
539                                 mask = Binary.Operator.NullableMask;
540                         } else {
541                                 underlying = EnumSpec.GetUnderlyingType (enumType);
542                         }
543
544                         var operators = new[] {
545                                 new Binary.PredefinedOperator (enumType, underlying,
546                                         mask | Binary.Operator.AdditionMask | Binary.Operator.SubtractionMask | Binary.Operator.DecomposedMask, enumType),
547                                 new Binary.PredefinedOperator (underlying, enumType,
548                                         mask | Binary.Operator.AdditionMask | Binary.Operator.SubtractionMask | Binary.Operator.DecomposedMask, enumType),
549                                 new Binary.PredefinedOperator (enumType, mask | Binary.Operator.SubtractionMask, underlying)
550                         };
551
552                         return operators;
553                 }
554
555                 public void InitializePredefinedTypes ()
556                 {
557                         predefined_attributes = new PredefinedAttributes (this);
558                         predefined_types = new PredefinedTypes (this);
559                         predefined_members = new PredefinedMembers (this);
560
561                         OperatorsBinaryEqualityLifted = Binary.CreateEqualityLiftedOperatorsTable (this);
562                         OperatorsBinaryLifted = Binary.CreateStandardLiftedOperatorsTable (this);
563                 }
564
565                 public override bool IsClsComplianceRequired ()
566                 {
567                         return DeclaringAssembly.IsCLSCompliant;
568                 }
569
570                 public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
571                 {
572                         Attribute a = OptAttributes.Search ("assembly", a_type);
573                         if (a != null) {
574                                 a.Resolve ();
575                         }
576                         return a;
577                 }
578
579                 public void SetDeclaringAssembly (AssemblyDefinition assembly)
580                 {
581                         // TODO: This setter is quite ugly but I have not found a way around it yet
582                         this.assembly = assembly;
583                 }
584         }
585 }