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 : CompilerGeneratedClass
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), Modifiers.STATIC)
47 size_types = new Dictionary<int, Struct> ();
50 public override void CloseContainer ()
52 base.CloseContainer ();
54 foreach (var entry in size_types) {
55 entry.Value.CloseContainer ();
59 public FieldSpec DefineInitializedData (byte[] data, Location loc)
62 if (!size_types.TryGetValue (data.Length, out size_type)) {
64 // Build common type for this data length. We cannot use
65 // DefineInitializedData because it creates public type,
66 // and its name is not unique among modules
68 size_type = new Struct (this, new MemberName ("$ArrayType=" + data.Length, loc), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, null);
69 size_type.CreateContainer ();
70 size_type.DefineContainer ();
72 size_types.Add (data.Length, size_type);
74 // It has to work even if StructLayoutAttribute does not exist
75 size_type.TypeBuilder.__SetLayout (1, data.Length);
78 var name = "$field-" + fields.ToString ("X");
80 const Modifiers fmod = Modifiers.STATIC | Modifiers.INTERNAL;
81 var fbuilder = TypeBuilder.DefineField (name, size_type.CurrentType.GetMetaInfo (), ModifiersExtensions.FieldAttr (fmod) | FieldAttributes.HasFieldRVA);
82 fbuilder.__SetDataAndRVA (data);
84 return new FieldSpec (CurrentType, null, size_type.CurrentType, fbuilder, fmod);
88 StaticDataContainer static_data;
91 // Makes const data field inside internal type container
93 public FieldSpec MakeStaticData (byte[] data, Location loc)
95 if (static_data == null) {
96 static_data = new StaticDataContainer (this);
97 static_data.CreateContainer ();
98 static_data.DefineContainer ();
100 AddCompilerGeneratedClass (static_data);
103 return static_data.DefineInitializedData (data, loc);
107 public CharSet? DefaultCharSet;
108 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
110 readonly Dictionary<int, List<AnonymousTypeClass>> anonymous_types;
111 readonly Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> array_types;
112 readonly Dictionary<TypeSpec, PointerContainer> pointer_types;
113 readonly Dictionary<TypeSpec, ReferenceContainer> reference_types;
114 readonly Dictionary<TypeSpec, MethodSpec> attrs_cache;
116 AssemblyDefinition assembly;
117 readonly CompilerContext context;
118 readonly RootNamespace global_ns;
119 readonly Dictionary<string, RootNamespace> alias_ns;
121 ModuleBuilder builder;
123 bool has_extenstion_method;
125 PredefinedAttributes predefined_attributes;
126 PredefinedTypes predefined_types;
127 PredefinedMembers predefined_members;
129 static readonly string[] attribute_targets = new string[] { "assembly", "module" };
131 public ModuleContainer (CompilerContext context)
132 : base (null, MemberName.Null, null, 0)
134 this.context = context;
136 caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected);
138 containers = new List<TypeContainer> ();
139 anonymous_types = new Dictionary<int, List<AnonymousTypeClass>> ();
140 global_ns = new GlobalRootNamespace ();
141 alias_ns = new Dictionary<string, RootNamespace> ();
142 array_types = new Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ();
143 pointer_types = new Dictionary<TypeSpec, PointerContainer> ();
144 reference_types = new Dictionary<TypeSpec, ReferenceContainer> ();
145 attrs_cache = new Dictionary<TypeSpec, MethodSpec> ();
150 internal Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ArrayTypesCache {
157 // Cache for parameter-less attributes
159 internal Dictionary<TypeSpec, MethodSpec> AttributeConstructorCache {
165 public override AttributeTargets AttributeTargets {
167 return AttributeTargets.Assembly;
171 public ModuleBuilder Builder {
177 public override CompilerContext Compiler {
183 public int CounterAnonymousTypes { get; set; }
184 public int CounterAnonymousMethods { get; set; }
185 public int CounterAnonymousContainers { get; set; }
186 public int CounterSwitchTypes { get; set; }
188 public AssemblyDefinition DeclaringAssembly {
194 internal DocumentationBuilder DocumentationBuilder {
198 public override string DocCommentHeader {
200 throw new NotSupportedException ();
204 public Evaluator Evaluator {
208 public bool HasDefaultCharSet {
210 return DefaultCharSet.HasValue;
214 public bool HasExtensionMethod {
216 return has_extenstion_method;
219 has_extenstion_method = value;
223 public bool HasTypesFullyDefined {
228 // Returns module global:: namespace
230 public RootNamespace GlobalRootNamespace {
236 public override ModuleContainer Module {
242 internal Dictionary<TypeSpec, PointerContainer> PointerTypesCache {
244 return pointer_types;
248 internal PredefinedAttributes PredefinedAttributes {
250 return predefined_attributes;
254 internal PredefinedMembers PredefinedMembers {
256 return predefined_members;
260 internal PredefinedTypes PredefinedTypes {
262 return predefined_types;
266 internal Dictionary<TypeSpec, ReferenceContainer> ReferenceTypesCache {
268 return reference_types;
272 public override string[] ValidAttributeTargets {
274 return attribute_targets;
280 public override void Accept (StructuralVisitor visitor)
282 visitor.Visit (this);
285 public void AddAnonymousType (AnonymousTypeClass type)
287 List<AnonymousTypeClass> existing;
288 if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing))
289 if (existing == null) {
290 existing = new List<AnonymousTypeClass> ();
291 anonymous_types.Add (type.Parameters.Count, existing);
297 public void AddAttribute (Attribute attr, IMemberContext context)
299 attr.AttachTo (this, context);
301 if (attributes == null) {
302 attributes = new Attributes (attr);
306 attributes.AddAttribute (attr);
309 public override void AddTypeContainer (TypeContainer tc)
314 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
316 if (a.Target == AttributeTargets.Assembly) {
317 assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
321 if (a.Type == pa.DefaultCharset) {
322 switch (a.GetCharSetValue ()) {
327 DefaultCharSet = CharSet.Auto;
328 DefaultCharSetType = TypeAttributes.AutoClass;
330 case CharSet.Unicode:
331 DefaultCharSet = CharSet.Unicode;
332 DefaultCharSetType = TypeAttributes.UnicodeClass;
335 Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid",
336 a.GetSignatureForError ());
339 } else if (a.Type == pa.CLSCompliant) {
340 Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
342 Report.Warning (3012, 1, a.Location,
343 "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
344 } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) {
345 Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ());
346 Report.Warning (3017, 1, a.Location,
347 "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
352 builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
355 public override void CloseContainer ()
357 if (anonymous_types != null) {
358 foreach (var atypes in anonymous_types)
359 foreach (var at in atypes.Value)
360 at.CloseContainer ();
363 base.CloseContainer ();
366 public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
368 return builder.DefineType (name, attr, null, typeSize);
372 // Creates alias global namespace
374 public RootNamespace CreateRootNamespace (string alias)
376 if (alias == global_ns.Alias) {
377 RootNamespace.Error_GlobalNamespaceRedefined (Report, Location.Null);
382 if (!alias_ns.TryGetValue (alias, out rn)) {
383 rn = new RootNamespace (alias);
384 alias_ns.Add (alias, rn);
390 public void Create (AssemblyDefinition assembly, ModuleBuilder moduleBuilder)
392 this.assembly = assembly;
393 builder = moduleBuilder;
396 public override bool Define ()
402 HasTypesFullyDefined = true;
407 public override bool DefineContainer ()
411 return base.DefineContainer ();
414 public override void EmitContainer ()
416 if (OptAttributes != null)
417 OptAttributes.Emit ();
419 if (Compiler.Settings.Unsafe) {
420 var pa = PredefinedAttributes.UnverifiableCode;
422 pa.EmitAttribute (builder);
425 foreach (var tc in containers) {
426 tc.DefineConstants ();
429 base.EmitContainer ();
431 if (Compiler.Report.Errors == 0)
434 if (anonymous_types != null) {
435 foreach (var atypes in anonymous_types)
436 foreach (var at in atypes.Value)
441 internal override void GenerateDocComment (DocumentationBuilder builder)
443 foreach (var tc in containers)
444 tc.GenerateDocComment (builder);
447 public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
449 List<AnonymousTypeClass> candidates;
450 if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
454 foreach (AnonymousTypeClass at in candidates) {
455 for (i = 0; i < parameters.Count; ++i) {
456 if (!parameters [i].Equals (at.Parameters [i]))
460 if (i == parameters.Count)
467 public override void GetCompletionStartingWith (string prefix, List<string> results)
469 var names = Evaluator.GetVarNames ();
470 results.AddRange (names.Where (l => l.StartsWith (prefix)));
473 public RootNamespace GetRootNamespace (string name)
476 alias_ns.TryGetValue (name, out rn);
480 public override string GetSignatureForError ()
485 public void InitializePredefinedTypes ()
487 predefined_attributes = new PredefinedAttributes (this);
488 predefined_types = new PredefinedTypes (this);
489 predefined_members = new PredefinedMembers (this);
492 public override bool IsClsComplianceRequired ()
494 return DeclaringAssembly.IsCLSCompliant;
497 public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
499 Attribute a = OptAttributes.Search ("assembly", a_type);
506 public void SetDeclaringAssembly (AssemblyDefinition assembly)
508 // TODO: This setter is quite ugly but I have not found a way around it yet
509 this.assembly = assembly;