2 // module.cs: keeps a tree representation of the generated code
4 // Authors: Miguel de Icaza (miguel@gnu.org)
5 // Marek Safar (marek.safar@gmail.com)
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 // Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 // Copyright 2003-2008 Novell, Inc.
11 // Copyright 2011 Xamarin Inc
15 using System.Collections.Generic;
16 using System.Runtime.InteropServices;
17 using Mono.CompilerServices.SymbolWriter;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
31 // Module (top-level type) container
33 public sealed class ModuleContainer : TypeContainer
37 // Compiler generated container for static data
39 sealed class StaticDataContainer : CompilerGeneratedContainer
41 readonly Dictionary<int, Struct> size_types;
44 public StaticDataContainer (ModuleContainer module)
45 : base (module, new MemberName ("<PrivateImplementationDetails>" + module.builder.ModuleVersionId.ToString ("B"), Location.Null),
46 Modifiers.STATIC | Modifiers.INTERNAL)
48 size_types = new Dictionary<int, Struct> ();
51 public override void CloseContainer ()
53 base.CloseContainer ();
55 foreach (var entry in size_types) {
56 entry.Value.CloseContainer ();
60 public FieldSpec DefineInitializedData (byte[] data, Location loc)
63 if (!size_types.TryGetValue (data.Length, out size_type)) {
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
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 ();
73 size_types.Add (data.Length, size_type);
75 // It has to work even if StructLayoutAttribute does not exist
76 size_type.TypeBuilder.__SetLayout (1, data.Length);
79 var name = "$field-" + fields.ToString ("X");
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);
85 return new FieldSpec (CurrentType, null, size_type.CurrentType, fbuilder, fmod);
89 StaticDataContainer static_data;
92 // Makes const data field inside internal type container
94 public FieldSpec MakeStaticData (byte[] data, Location loc)
96 if (static_data == null) {
97 static_data = new StaticDataContainer (this);
98 static_data.CreateContainer ();
99 static_data.DefineContainer ();
101 AddCompilerGeneratedClass (static_data);
104 return static_data.DefineInitializedData (data, loc);
108 public CharSet? DefaultCharSet;
109 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
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;
118 AssemblyDefinition assembly;
119 readonly CompilerContext context;
120 readonly RootNamespace global_ns;
121 readonly Dictionary<string, RootNamespace> alias_ns;
123 ModuleBuilder builder;
125 bool has_extenstion_method;
127 PredefinedAttributes predefined_attributes;
128 PredefinedTypes predefined_types;
129 PredefinedMembers predefined_members;
131 public Binary.PredefinedOperator[] OperatorsBinaryEqualityLifted;
132 public Binary.PredefinedOperator[] OperatorsBinaryLifted;
134 static readonly string[] attribute_targets = new string[] { "assembly", "module" };
136 public ModuleContainer (CompilerContext context)
137 : base (null, MemberName.Null, null, 0)
139 this.context = context;
141 caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected);
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> ();
156 internal Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ArrayTypesCache {
163 // Cache for parameter-less attributes
165 internal Dictionary<TypeSpec, MethodSpec> AttributeConstructorCache {
171 public override AttributeTargets AttributeTargets {
173 return AttributeTargets.Assembly;
177 public ModuleBuilder Builder {
183 public override CompilerContext Compiler {
189 public int CounterAnonymousTypes { get; set; }
190 public int CounterAnonymousMethods { get; set; }
191 public int CounterAnonymousContainers { get; set; }
192 public int CounterSwitchTypes { get; set; }
194 public AssemblyDefinition DeclaringAssembly {
200 internal DocumentationBuilder DocumentationBuilder {
204 public override string DocCommentHeader {
206 throw new NotSupportedException ();
210 public Evaluator Evaluator {
214 public bool HasDefaultCharSet {
216 return DefaultCharSet.HasValue;
220 public bool HasExtensionMethod {
222 return has_extenstion_method;
225 has_extenstion_method = value;
229 public bool HasTypesFullyDefined {
234 // Returns module global:: namespace
236 public RootNamespace GlobalRootNamespace {
242 public override ModuleContainer Module {
248 internal Dictionary<TypeSpec, PointerContainer> PointerTypesCache {
250 return pointer_types;
254 internal PredefinedAttributes PredefinedAttributes {
256 return predefined_attributes;
260 internal PredefinedMembers PredefinedMembers {
262 return predefined_members;
266 internal PredefinedTypes PredefinedTypes {
268 return predefined_types;
272 internal Dictionary<TypeSpec, ReferenceContainer> ReferenceTypesCache {
274 return reference_types;
278 public override string[] ValidAttributeTargets {
280 return attribute_targets;
286 public override void Accept (StructuralVisitor visitor)
288 visitor.Visit (this);
291 public void AddAnonymousType (AnonymousTypeClass type)
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);
303 public void AddAttribute (Attribute attr, IMemberContext context)
305 attr.AttachTo (this, context);
307 if (attributes == null) {
308 attributes = new Attributes (attr);
312 attributes.AddAttribute (attr);
315 public override void AddTypeContainer (TypeContainer tc)
317 AddTypeContainerMember (tc);
320 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
322 if (a.Target == AttributeTargets.Assembly) {
323 assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
327 if (a.Type == pa.DefaultCharset) {
328 switch (a.GetCharSetValue ()) {
333 DefaultCharSet = CharSet.Auto;
334 DefaultCharSetType = TypeAttributes.AutoClass;
336 case CharSet.Unicode:
337 DefaultCharSet = CharSet.Unicode;
338 DefaultCharSetType = TypeAttributes.UnicodeClass;
341 Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid",
342 a.GetSignatureForError ());
345 } else if (a.Type == pa.CLSCompliant) {
346 Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
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");
358 builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
361 public override void CloseContainer ()
363 if (anonymous_types != null) {
364 foreach (var atypes in anonymous_types)
365 foreach (var at in atypes.Value)
366 at.CloseContainer ();
369 base.CloseContainer ();
372 public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
374 return builder.DefineType (name, attr, null, typeSize);
378 // Creates alias global namespace
380 public RootNamespace CreateRootNamespace (string alias)
382 if (alias == global_ns.Alias) {
383 RootNamespace.Error_GlobalNamespaceRedefined (Report, Location.Null);
388 if (!alias_ns.TryGetValue (alias, out rn)) {
389 rn = new RootNamespace (alias);
390 alias_ns.Add (alias, rn);
396 public void Create (AssemblyDefinition assembly, ModuleBuilder moduleBuilder)
398 this.assembly = assembly;
399 builder = moduleBuilder;
402 public override bool Define ()
406 ExpandBaseInterfaces ();
410 HasTypesFullyDefined = true;
415 public override bool DefineContainer ()
419 return base.DefineContainer ();
422 public void EnableRedefinition ()
427 public override void EmitContainer ()
429 if (OptAttributes != null)
430 OptAttributes.Emit ();
432 if (Compiler.Settings.Unsafe && !assembly.IsSatelliteAssembly) {
433 var pa = PredefinedAttributes.UnverifiableCode;
435 pa.EmitAttribute (builder);
438 foreach (var tc in containers) {
442 base.EmitContainer ();
444 if (Compiler.Report.Errors == 0 && !Compiler.Settings.WriteMetadataOnly)
447 if (anonymous_types != null) {
448 foreach (var atypes in anonymous_types)
449 foreach (var at in atypes.Value)
454 internal override void GenerateDocComment (DocumentationBuilder builder)
456 foreach (var tc in containers)
457 tc.GenerateDocComment (builder);
460 public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
462 List<AnonymousTypeClass> candidates;
463 if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
467 foreach (AnonymousTypeClass at in candidates) {
468 for (i = 0; i < parameters.Count; ++i) {
469 if (!parameters [i].Equals (at.Parameters [i]))
473 if (i == parameters.Count)
481 // Return container with awaiter definition. It never returns null
482 // but all container member can be null for easier error reporting
484 public AwaiterDefinition GetAwaiter (TypeSpec type)
486 AwaiterDefinition awaiter;
487 if (awaiters.TryGetValue (type, out awaiter))
490 awaiter = new AwaiterDefinition ();
493 // Predefined: bool IsCompleted { get; }
495 awaiter.IsCompleted = MemberCache.FindMember (type, MemberFilter.Property ("IsCompleted", Compiler.BuiltinTypes.Bool),
496 BindingRestriction.InstanceOnly) as PropertySpec;
499 // Predefined: GetResult ()
501 // The method return type is also result type of await expression
503 awaiter.GetResult = MemberCache.FindMember (type, MemberFilter.Method ("GetResult", 0,
504 ParametersCompiled.EmptyReadOnlyParameters, null),
505 BindingRestriction.InstanceOnly) as MethodSpec;
508 // Predefined: INotifyCompletion.OnCompleted (System.Action)
510 var nc = PredefinedTypes.INotifyCompletion;
511 awaiter.INotifyCompletion = !nc.Define () || type.ImplementsInterface (nc.TypeSpec, false);
513 awaiters.Add (type, awaiter);
517 public override void GetCompletionStartingWith (string prefix, List<string> results)
519 var names = Evaluator.GetVarNames ();
520 results.AddRange (names.Where (l => l.StartsWith (prefix)));
523 public RootNamespace GetRootNamespace (string name)
526 alias_ns.TryGetValue (name, out rn);
530 public override string GetSignatureForError ()
535 public Binary.PredefinedOperator[] GetPredefinedEnumAritmeticOperators (TypeSpec enumType, bool nullable)
538 Binary.Operator mask = 0;
541 underlying = Nullable.NullableInfo.GetEnumUnderlyingType (this, enumType);
542 mask = Binary.Operator.NullableMask;
544 underlying = EnumSpec.GetUnderlyingType (enumType);
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)
558 public void InitializePredefinedTypes ()
560 predefined_attributes = new PredefinedAttributes (this);
561 predefined_types = new PredefinedTypes (this);
562 predefined_members = new PredefinedMembers (this);
564 OperatorsBinaryEqualityLifted = Binary.CreateEqualityLiftedOperatorsTable (this);
565 OperatorsBinaryLifted = Binary.CreateStandardLiftedOperatorsTable (this);
568 public override bool IsClsComplianceRequired ()
570 return DeclaringAssembly.IsCLSCompliant;
573 public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
575 Attribute a = OptAttributes.Search ("assembly", a_type);
582 public void SetDeclaringAssembly (AssemblyDefinition assembly)
584 // TODO: This setter is quite ugly but I have not found a way around it yet
585 this.assembly = assembly;