// // module.cs: keeps a tree representation of the generated code // // Authors: Miguel de Icaza (miguel@gnu.org) // Marek Safar (marek.safar@gmail.com) // // Dual licensed under the terms of the MIT X11 or GNU GPL // // Copyright 2001-2003 Ximian, Inc (http://www.ximian.com) // Copyright 2003-2008 Novell, Inc. // Copyright 2011 Xamarin Inc // using System; using System.Collections.Generic; using System.Runtime.InteropServices; using Mono.CompilerServices.SymbolWriter; using System.Linq; #if STATIC using IKVM.Reflection; using IKVM.Reflection.Emit; #else using System.Reflection; using System.Reflection.Emit; #endif namespace Mono.CSharp { // // Module (top-level type) container // public sealed class ModuleContainer : TypeContainer { #if STATIC // // Compiler generated container for static data // sealed class StaticDataContainer : CompilerGeneratedClass { readonly Dictionary size_types; int fields; public StaticDataContainer (ModuleContainer module) : base (module, new MemberName ("" + module.builder.ModuleVersionId.ToString ("B"), Location.Null), Modifiers.STATIC) { size_types = new Dictionary (); } public override void CloseContainer () { base.CloseContainer (); foreach (var entry in size_types) { entry.Value.CloseContainer (); } } public FieldSpec DefineInitializedData (byte[] data, Location loc) { Struct size_type; if (!size_types.TryGetValue (data.Length, out size_type)) { // // Build common type for this data length. We cannot use // DefineInitializedData because it creates public type, // and its name is not unique among modules // size_type = new Struct (this, new MemberName ("$ArrayType=" + data.Length, loc), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, null); size_type.CreateContainer (); size_type.DefineContainer (); size_types.Add (data.Length, size_type); // It has to work even if StructLayoutAttribute does not exist size_type.TypeBuilder.__SetLayout (1, data.Length); } var name = "$field-" + fields.ToString ("X"); ++fields; const Modifiers fmod = Modifiers.STATIC | Modifiers.INTERNAL; var fbuilder = TypeBuilder.DefineField (name, size_type.CurrentType.GetMetaInfo (), ModifiersExtensions.FieldAttr (fmod) | FieldAttributes.HasFieldRVA); fbuilder.__SetDataAndRVA (data); return new FieldSpec (CurrentType, null, size_type.CurrentType, fbuilder, fmod); } } StaticDataContainer static_data; // // Makes const data field inside internal type container // public FieldSpec MakeStaticData (byte[] data, Location loc) { if (static_data == null) { static_data = new StaticDataContainer (this); static_data.CreateContainer (); static_data.DefineContainer (); AddCompilerGeneratedClass (static_data); } return static_data.DefineInitializedData (data, loc); } #endif public CharSet? DefaultCharSet; public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass; readonly Dictionary> anonymous_types; readonly Dictionary array_types; readonly Dictionary pointer_types; readonly Dictionary reference_types; readonly Dictionary attrs_cache; AssemblyDefinition assembly; readonly CompilerContext context; readonly RootNamespace global_ns; readonly Dictionary alias_ns; ModuleBuilder builder; bool has_extenstion_method; PredefinedAttributes predefined_attributes; PredefinedTypes predefined_types; PredefinedMembers predefined_members; static readonly string[] attribute_targets = new string[] { "assembly", "module" }; public ModuleContainer (CompilerContext context) : base (null, MemberName.Null, null, 0) { this.context = context; caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected); containers = new List (); anonymous_types = new Dictionary> (); global_ns = new GlobalRootNamespace (); alias_ns = new Dictionary (); array_types = new Dictionary (); pointer_types = new Dictionary (); reference_types = new Dictionary (); attrs_cache = new Dictionary (); } #region Properties internal Dictionary ArrayTypesCache { get { return array_types; } } // // Cache for parameter-less attributes // internal Dictionary AttributeConstructorCache { get { return attrs_cache; } } public override AttributeTargets AttributeTargets { get { return AttributeTargets.Assembly; } } public ModuleBuilder Builder { get { return builder; } } public override CompilerContext Compiler { get { return context; } } public AssemblyDefinition DeclaringAssembly { get { return assembly; } } internal DocumentationBuilder DocumentationBuilder { get; set; } public override string DocCommentHeader { get { throw new NotSupportedException (); } } public Evaluator Evaluator { get; set; } public bool HasDefaultCharSet { get { return DefaultCharSet.HasValue; } } public bool HasExtensionMethod { get { return has_extenstion_method; } set { has_extenstion_method = value; } } public bool HasTypesFullyDefined { get; set; } // // Returns module global:: namespace // public RootNamespace GlobalRootNamespace { get { return global_ns; } } public override ModuleContainer Module { get { return this; } } internal Dictionary PointerTypesCache { get { return pointer_types; } } internal PredefinedAttributes PredefinedAttributes { get { return predefined_attributes; } } internal PredefinedMembers PredefinedMembers { get { return predefined_members; } } internal PredefinedTypes PredefinedTypes { get { return predefined_types; } } internal Dictionary ReferenceTypesCache { get { return reference_types; } } public override string[] ValidAttributeTargets { get { return attribute_targets; } } #endregion public override void Accept (StructuralVisitor visitor) { visitor.Visit (this); } public void AddAnonymousType (AnonymousTypeClass type) { List existing; if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing)) if (existing == null) { existing = new List (); anonymous_types.Add (type.Parameters.Count, existing); } existing.Add (type); } public void AddAttribute (Attribute attr, IMemberContext context) { attr.AttachTo (this, context); if (attributes == null) { attributes = new Attributes (attr); return; } attributes.AddAttribute (attr); } public override void AddTypeContainer (TypeContainer tc) { containers.Add (tc); } public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa) { if (a.Target == AttributeTargets.Assembly) { assembly.ApplyAttributeBuilder (a, ctor, cdata, pa); return; } if (a.Type == pa.DefaultCharset) { switch (a.GetCharSetValue ()) { case CharSet.Ansi: case CharSet.None: break; case CharSet.Auto: DefaultCharSet = CharSet.Auto; DefaultCharSetType = TypeAttributes.AutoClass; break; case CharSet.Unicode: DefaultCharSet = CharSet.Unicode; DefaultCharSetType = TypeAttributes.UnicodeClass; break; default: Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid", a.GetSignatureForError ()); break; } } else if (a.Type == pa.CLSCompliant) { Attribute cls = DeclaringAssembly.CLSCompliantAttribute; if (cls == null) { Report.Warning (3012, 1, a.Location, "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking"); } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) { Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ()); Report.Warning (3017, 1, a.Location, "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly"); return; } } builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata); } public override void CloseContainer () { if (anonymous_types != null) { foreach (var atypes in anonymous_types) foreach (var at in atypes.Value) at.CloseContainer (); } base.CloseContainer (); } public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize) { return builder.DefineType (name, attr, null, typeSize); } // // Creates alias global namespace // public RootNamespace CreateRootNamespace (string alias) { if (alias == global_ns.Alias) { RootNamespace.Error_GlobalNamespaceRedefined (Report, Location.Null); return global_ns; } RootNamespace rn; if (!alias_ns.TryGetValue (alias, out rn)) { rn = new RootNamespace (alias); alias_ns.Add (alias, rn); } return rn; } public void Create (AssemblyDefinition assembly, ModuleBuilder moduleBuilder) { this.assembly = assembly; builder = moduleBuilder; } public override bool Define () { DefineContainer (); base.Define (); HasTypesFullyDefined = true; return true; } public override bool DefineContainer () { DefineNamespace (); return base.DefineContainer (); } public override void EmitContainer () { if (OptAttributes != null) OptAttributes.Emit (); if (Compiler.Settings.Unsafe) { var pa = PredefinedAttributes.UnverifiableCode; if (pa.IsDefined) pa.EmitAttribute (builder); } foreach (var tc in containers) { tc.DefineConstants (); } base.EmitContainer (); if (Compiler.Report.Errors == 0) VerifyMembers (); if (anonymous_types != null) { foreach (var atypes in anonymous_types) foreach (var at in atypes.Value) at.EmitContainer (); } } internal override void GenerateDocComment (DocumentationBuilder builder) { foreach (var tc in containers) tc.GenerateDocComment (builder); } public AnonymousTypeClass GetAnonymousType (IList parameters) { List candidates; if (!anonymous_types.TryGetValue (parameters.Count, out candidates)) return null; int i; foreach (AnonymousTypeClass at in candidates) { for (i = 0; i < parameters.Count; ++i) { if (!parameters [i].Equals (at.Parameters [i])) break; } if (i == parameters.Count) return at; } return null; } public override void GetCompletionStartingWith (string prefix, List results) { var names = Evaluator.GetVarNames (); results.AddRange (names.Where (l => l.StartsWith (prefix))); } public RootNamespace GetRootNamespace (string name) { RootNamespace rn; alias_ns.TryGetValue (name, out rn); return rn; } public override string GetSignatureForError () { return ""; } public void InitializePredefinedTypes () { predefined_attributes = new PredefinedAttributes (this); predefined_types = new PredefinedTypes (this); predefined_members = new PredefinedMembers (this); } public override bool IsClsComplianceRequired () { return DeclaringAssembly.IsCLSCompliant; } public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type) { Attribute a = OptAttributes.Search ("assembly", a_type); if (a != null) { a.Resolve (); } return a; } public void SetDeclaringAssembly (AssemblyDefinition assembly) { // TODO: This setter is quite ugly but I have not found a way around it yet this.assembly = assembly; } } }