X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Froottypes.cs;h=48f2b266b3b7637a15fdbf0c15a8dfebc27f70c6;hb=f574f7b447e29c6f083fcad4e6dc5f89d3cb4b4d;hp=bfc7f7b8d28494078fb90e2f4c65033ed97ea191;hpb=d49951ccf584ba637afb1dab7fff714478e3174d;p=mono.git diff --git a/mcs/mcs/roottypes.cs b/mcs/mcs/roottypes.cs index bfc7f7b8d28..48f2b266b3b 100644 --- a/mcs/mcs/roottypes.cs +++ b/mcs/mcs/roottypes.cs @@ -1,105 +1,627 @@ // // roottypes.cs: keeps a tree representation of the generated code // -// Author: Miguel de Icaza (miguel@gnu.org) +// Authors: Miguel de Icaza (miguel@gnu.org) +// Marek Safar (marek.safar@gmail.com) // -// Licensed under the terms of the GNU GPL -// -// (C) 2001 Ximian, Inc (http://www.ximian.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; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Mono.CompilerServices.SymbolWriter; + +#if STATIC +using IKVM.Reflection; +using IKVM.Reflection.Emit; +#else using System.Reflection; using System.Reflection.Emit; -using System.IO; +#endif namespace Mono.CSharp { - // - // We store here all the toplevel types that we have parsed, - // this is the root of all information we have parsed. - // - public sealed class RootTypes : TypeContainer + // + // Module (top-level type) container + // + public sealed class ModuleContainer : TypeContainer { - public RootTypes () - : base (null, null, MemberName.Null, null, Kind.Root) +#if STATIC + // + // Compiler generated container for static data + // + sealed class StaticDataContainer : CompilerGeneratedClass { - types = new ArrayList (); + readonly Dictionary size_types; + new 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 CloseType () + { + base.CloseType (); + + foreach (var entry in size_types) { + entry.Value.CloseType (); + } + } + + 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 (null, this, new MemberName ("$ArrayType=" + data.Length, loc), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, null); + size_type.CreateType (); + size_type.DefineType (); + + 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); + } } - public override bool IsClsComplianceRequired () + 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.CreateType (); + static_data.DefineType (); + + 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; + + // Used for unique namespaces/types during parsing + Dictionary defined_type_containers; + + 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, null, MemberName.Null, null, 0) + { + this.context = context; + + caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected); + + types = 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 (); + + defined_type_containers = 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 override AssemblyDefinition DeclaringAssembly { + get { + return assembly; + } + } + + internal DocumentationBuilder DocumentationBuilder { + get; set; + } + + 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) { - return true; + attr.AttachTo (this, context); + + if (attributes == null) { + attributes = new Attributes (attr); + return; + } + + attributes.AddAttribute (attr); } - public override bool GetClsCompliantAttributeValue () + public override TypeContainer AddPartial (TypeContainer nextPart) { - return CodeGen.Assembly.IsClsCompliant; + return AddPartial (nextPart, nextPart.Name); + } + + 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 CloseType () + { + foreach (TypeContainer tc in types) { + tc.CloseType (); + } + + if (compiler_generated != null) + foreach (CompilerGeneratedClass c in compiler_generated) + c.CloseType (); + } + + 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 new void CreateType () + { + // Release cache used by parser only + if (Evaluator == null) + defined_type_containers = null; + else + defined_type_containers.Clear (); + + foreach (TypeContainer tc in types) + tc.CreateType (); + } + + public new void Define () + { + foreach (TypeContainer tc in types) { + try { + tc.DefineType (); + } catch (Exception e) { + throw new InternalErrorException (tc, e); + } + } + + foreach (TypeContainer tc in types) + tc.ResolveTypeParameters (); + + foreach (TypeContainer tc in types) { + try { + tc.Define (); + } catch (Exception e) { + throw new InternalErrorException (tc, e); + } + } + + HasTypesFullyDefined = true; + } + + public override void Emit () + { + if (OptAttributes != null) + OptAttributes.Emit (); + + if (Compiler.Settings.Unsafe) { + var pa = PredefinedAttributes.UnverifiableCode; + if (pa.IsDefined) + pa.EmitAttribute (builder); + } + + foreach (var tc in types) + tc.DefineConstants (); + + foreach (TypeContainer tc in types) + tc.EmitType (); + + if (Compiler.Report.Errors > 0) + return; + + foreach (TypeContainer tc in types) + tc.VerifyMembers (); + + if (compiler_generated != null) + foreach (var c in compiler_generated) + c.EmitType (); + } + + internal override void GenerateDocComment (DocumentationBuilder builder) + { + foreach (var tc in types) + 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 RootNamespace GetRootNamespace (string name) + { + RootNamespace rn; + alias_ns.TryGetValue (name, out rn); + return rn; } public override string GetSignatureForError () { - return ""; + 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; + } + + protected override bool AddMemberType (TypeContainer tc) + { + if (AddTypesContainer (tc)) { + if ((tc.ModFlags & Modifiers.PARTIAL) != 0) + defined_names.Add (tc.Name, tc); + + tc.NamespaceEntry.NS.AddType (this, tc.Definition); + return true; + } + + return false; + } + + public bool AddTypesContainer (ITypesContainer container) + { + var mn = container.MemberName; + ITypesContainer found; + if (!defined_type_containers.TryGetValue (mn, out found)) { + defined_type_containers.Add (mn, container); + return true; + } + + if (container is NamespaceContainer && found is NamespaceContainer) + return true; + + var container_tc = container as TypeContainer; + var found_tc = found as TypeContainer; + if (container_tc != null && found_tc != null && container_tc.Kind == found_tc.Kind) { + if ((found_tc.ModFlags & container_tc.ModFlags & Modifiers.PARTIAL) != 0) { + return false; + } + + if (((found_tc.ModFlags | container_tc.ModFlags) & Modifiers.PARTIAL) != 0) { + Report.SymbolRelatedToPreviousError (found_tc); + Error_MissingPartialModifier (container_tc); + return false; + } + } + + string ns = mn.Left != null ? mn.Left.GetSignatureForError () : Module.GlobalRootNamespace.GetSignatureForError (); + mn = new MemberName (mn.Name, mn.TypeArguments, mn.Location); + + Report.SymbolRelatedToPreviousError (found.Location, ""); + Report.Error (101, container.Location, + "The namespace `{0}' already contains a definition for `{1}'", + ns, mn.GetSignatureForError ()); + return false; + } + + protected override void RemoveMemberType (TypeContainer ds) + { + defined_type_containers.Remove (ds.MemberName); + ds.NamespaceEntry.NS.RemoveDeclSpace (ds.Basename); + base.RemoveMemberType (ds); } - protected override bool AddMemberType (DeclSpace ds) + public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type) { - if (!AddToContainer (ds, ds.Name)) - return false; - ds.NamespaceEntry.NS.AddDeclSpace (ds.Basename, ds); - return true; + Attribute a = OptAttributes.Search ("assembly", a_type); + if (a != null) { + a.Resolve (); + } + return a; } - public override TypeContainer AddPartial (TypeContainer nextPart, bool is_interface) + public void SetDeclaringAssembly (AssemblyDefinition assembly) { - return AddPartial (nextPart, nextPart.Name, is_interface); + // TODO: This setter is quite ugly but I have not found a way around it yet + this.assembly = assembly; } } - public class RootDeclSpace : DeclSpace { - public RootDeclSpace (NamespaceEntry ns) - : base (ns, null, MemberName.Null, null) + sealed class RootDeclSpace : TypeContainer { + public RootDeclSpace (ModuleContainer module, NamespaceContainer ns) + : base (ns, null, MemberName.Null, null, 0) { - PartialContainer = RootContext.ToplevelTypes; + PartialContainer = module; } public override AttributeTargets AttributeTargets { get { throw new InternalErrorException ("should not be called"); } } + public override CompilerContext Compiler { + get { + return PartialContainer.Compiler; + } + } + public override string DocCommentHeader { get { throw new InternalErrorException ("should not be called"); } } - public override bool Define () + public override void DefineType () { throw new InternalErrorException ("should not be called"); } - public override TypeBuilder DefineType () - { - throw new InternalErrorException ("should not be called"); + public override ModuleContainer Module { + get { + return PartialContainer.Module; + } } - public override MemberList FindMembers (MemberTypes mt, BindingFlags bf, MemberFilter filter, object criteria) + public override void Accept (StructuralVisitor visitor) { throw new InternalErrorException ("should not be called"); } - public override MemberCache MemberCache { - get { return PartialContainer.MemberCache; } + public override bool IsClsComplianceRequired () + { + return PartialContainer.IsClsComplianceRequired (); } - public override bool GetClsCompliantAttributeValue () + public override ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity) { - return PartialContainer.GetClsCompliantAttributeValue (); + return null; } - public override bool IsClsComplianceRequired () + public override FullNamedExpression LookupNamespaceAlias (string name) { - return PartialContainer.IsClsComplianceRequired (); + return NamespaceEntry.LookupNamespaceAlias (name); } } }