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 AssemblyDefinition DeclaringAssembly {
189 internal DocumentationBuilder DocumentationBuilder {
193 public override string DocCommentHeader {
195 throw new NotSupportedException ();
199 public Evaluator Evaluator {
203 public bool HasDefaultCharSet {
205 return DefaultCharSet.HasValue;
209 public bool HasExtensionMethod {
211 return has_extenstion_method;
214 has_extenstion_method = value;
218 public bool HasTypesFullyDefined {
223 // Returns module global:: namespace
225 public RootNamespace GlobalRootNamespace {
231 public override ModuleContainer Module {
237 internal Dictionary<TypeSpec, PointerContainer> PointerTypesCache {
239 return pointer_types;
243 internal PredefinedAttributes PredefinedAttributes {
245 return predefined_attributes;
249 internal PredefinedMembers PredefinedMembers {
251 return predefined_members;
255 internal PredefinedTypes PredefinedTypes {
257 return predefined_types;
261 internal Dictionary<TypeSpec, ReferenceContainer> ReferenceTypesCache {
263 return reference_types;
267 public override string[] ValidAttributeTargets {
269 return attribute_targets;
275 public override void Accept (StructuralVisitor visitor)
277 visitor.Visit (this);
280 public void AddAnonymousType (AnonymousTypeClass type)
282 List<AnonymousTypeClass> existing;
283 if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing))
284 if (existing == null) {
285 existing = new List<AnonymousTypeClass> ();
286 anonymous_types.Add (type.Parameters.Count, existing);
292 public void AddAttribute (Attribute attr, IMemberContext context)
294 attr.AttachTo (this, context);
296 if (attributes == null) {
297 attributes = new Attributes (attr);
301 attributes.AddAttribute (attr);
304 public override void AddTypeContainer (TypeContainer tc)
309 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
311 if (a.Target == AttributeTargets.Assembly) {
312 assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
316 if (a.Type == pa.DefaultCharset) {
317 switch (a.GetCharSetValue ()) {
322 DefaultCharSet = CharSet.Auto;
323 DefaultCharSetType = TypeAttributes.AutoClass;
325 case CharSet.Unicode:
326 DefaultCharSet = CharSet.Unicode;
327 DefaultCharSetType = TypeAttributes.UnicodeClass;
330 Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid",
331 a.GetSignatureForError ());
334 } else if (a.Type == pa.CLSCompliant) {
335 Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
337 Report.Warning (3012, 1, a.Location,
338 "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
339 } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) {
340 Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ());
341 Report.Warning (3017, 1, a.Location,
342 "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
347 builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
350 public override void CloseContainer ()
352 if (anonymous_types != null) {
353 foreach (var atypes in anonymous_types)
354 foreach (var at in atypes.Value)
355 at.CloseContainer ();
358 base.CloseContainer ();
361 public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
363 return builder.DefineType (name, attr, null, typeSize);
367 // Creates alias global namespace
369 public RootNamespace CreateRootNamespace (string alias)
371 if (alias == global_ns.Alias) {
372 RootNamespace.Error_GlobalNamespaceRedefined (Report, Location.Null);
377 if (!alias_ns.TryGetValue (alias, out rn)) {
378 rn = new RootNamespace (alias);
379 alias_ns.Add (alias, rn);
385 public void Create (AssemblyDefinition assembly, ModuleBuilder moduleBuilder)
387 this.assembly = assembly;
388 builder = moduleBuilder;
391 public override bool Define ()
397 HasTypesFullyDefined = true;
402 public override bool DefineContainer ()
406 return base.DefineContainer ();
409 public override void EmitContainer ()
411 if (OptAttributes != null)
412 OptAttributes.Emit ();
414 if (Compiler.Settings.Unsafe) {
415 var pa = PredefinedAttributes.UnverifiableCode;
417 pa.EmitAttribute (builder);
420 foreach (var tc in containers) {
421 tc.DefineConstants ();
424 base.EmitContainer ();
426 if (Compiler.Report.Errors == 0)
429 if (anonymous_types != null) {
430 foreach (var atypes in anonymous_types)
431 foreach (var at in atypes.Value)
436 internal override void GenerateDocComment (DocumentationBuilder builder)
438 foreach (var tc in containers)
439 tc.GenerateDocComment (builder);
442 public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
444 List<AnonymousTypeClass> candidates;
445 if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
449 foreach (AnonymousTypeClass at in candidates) {
450 for (i = 0; i < parameters.Count; ++i) {
451 if (!parameters [i].Equals (at.Parameters [i]))
455 if (i == parameters.Count)
462 public override void GetCompletionStartingWith (string prefix, List<string> results)
464 var names = Evaluator.GetVarNames ();
465 results.AddRange (names.Where (l => l.StartsWith (prefix)));
468 public RootNamespace GetRootNamespace (string name)
471 alias_ns.TryGetValue (name, out rn);
475 public override string GetSignatureForError ()
480 public void InitializePredefinedTypes ()
482 predefined_attributes = new PredefinedAttributes (this);
483 predefined_types = new PredefinedTypes (this);
484 predefined_members = new PredefinedMembers (this);
487 public override bool IsClsComplianceRequired ()
489 return DeclaringAssembly.IsCLSCompliant;
492 public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
494 Attribute a = OptAttributes.Search ("assembly", a_type);
501 public void SetDeclaringAssembly (AssemblyDefinition assembly)
503 // TODO: This setter is quite ugly but I have not found a way around it yet
504 this.assembly = assembly;