2 // roottypes.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.
14 using System.Collections.Generic;
15 using System.Runtime.InteropServices;
16 using Mono.CompilerServices.SymbolWriter;
19 using IKVM.Reflection;
20 using IKVM.Reflection.Emit;
22 using System.Reflection;
23 using System.Reflection.Emit;
29 // Module (top-level type) container
31 public sealed class ModuleContainer : TypeContainer
35 // Compiler generated container for static data
37 sealed class StaticDataContainer : CompilerGeneratedClass
39 readonly Dictionary<int, Struct> size_types;
42 public StaticDataContainer (ModuleContainer module)
43 : base (module, new MemberName ("<PrivateImplementationDetails>" + module.builder.ModuleVersionId.ToString ("B"), Location.Null), Modifiers.STATIC)
45 size_types = new Dictionary<int, Struct> ();
48 public override void CloseType ()
52 foreach (var entry in size_types) {
53 entry.Value.CloseType ();
57 public FieldSpec DefineInitializedData (byte[] data, Location loc)
60 if (!size_types.TryGetValue (data.Length, out size_type)) {
62 // Build common type for this data length. We cannot use
63 // DefineInitializedData because it creates public type,
64 // and its name is not unique among modules
66 size_type = new Struct (null, this, new MemberName ("$ArrayType=" + data.Length, loc), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, null);
67 size_type.CreateType ();
68 size_type.DefineType ();
70 size_types.Add (data.Length, size_type);
72 // It has to work even if StructLayoutAttribute does not exist
73 size_type.TypeBuilder.__SetLayout (1, data.Length);
76 var name = "$field-" + fields.ToString ("X");
78 const Modifiers fmod = Modifiers.STATIC | Modifiers.INTERNAL;
79 var fbuilder = TypeBuilder.DefineField (name, size_type.CurrentType.GetMetaInfo (), ModifiersExtensions.FieldAttr (fmod) | FieldAttributes.HasFieldRVA);
80 fbuilder.__SetDataAndRVA (data);
82 return new FieldSpec (CurrentType, null, size_type.CurrentType, fbuilder, fmod);
86 StaticDataContainer static_data;
89 // Makes const data field inside internal type container
91 public FieldSpec MakeStaticData (byte[] data, Location loc)
93 if (static_data == null) {
94 static_data = new StaticDataContainer (this);
95 static_data.CreateType ();
96 static_data.DefineType ();
98 AddCompilerGeneratedClass (static_data);
101 return static_data.DefineInitializedData (data, loc);
105 public CharSet? DefaultCharSet;
106 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
108 readonly Dictionary<int, List<AnonymousTypeClass>> anonymous_types;
109 readonly Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> array_types;
110 readonly Dictionary<TypeSpec, PointerContainer> pointer_types;
111 readonly Dictionary<TypeSpec, ReferenceContainer> reference_types;
112 readonly Dictionary<TypeSpec, MethodSpec> attrs_cache;
114 // Used for unique namespaces/types during parsing
115 Dictionary<MemberName, ITypesContainer> defined_type_containers;
117 AssemblyDefinition assembly;
118 readonly CompilerContext context;
119 readonly RootNamespace global_ns;
120 readonly Dictionary<string, RootNamespace> alias_ns;
122 ModuleBuilder builder;
124 bool has_extenstion_method;
126 PredefinedAttributes predefined_attributes;
127 PredefinedTypes predefined_types;
128 PredefinedMembers predefined_members;
130 static readonly string[] attribute_targets = new string[] { "assembly", "module" };
132 public ModuleContainer (CompilerContext context)
133 : base (null, null, MemberName.Null, null, 0)
135 this.context = context;
137 caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected);
139 types = new List<TypeContainer> ();
140 anonymous_types = new Dictionary<int, List<AnonymousTypeClass>> ();
141 global_ns = new GlobalRootNamespace ();
142 alias_ns = new Dictionary<string, RootNamespace> ();
143 array_types = new Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ();
144 pointer_types = new Dictionary<TypeSpec, PointerContainer> ();
145 reference_types = new Dictionary<TypeSpec, ReferenceContainer> ();
146 attrs_cache = new Dictionary<TypeSpec, MethodSpec> ();
148 defined_type_containers = new Dictionary<MemberName, ITypesContainer> ();
153 internal Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ArrayTypesCache {
160 // Cache for parameter-less attributes
162 internal Dictionary<TypeSpec, MethodSpec> AttributeConstructorCache {
168 public override AttributeTargets AttributeTargets {
170 return AttributeTargets.Assembly;
174 public ModuleBuilder Builder {
180 public override CompilerContext Compiler {
186 public override AssemblyDefinition DeclaringAssembly {
192 internal DocumentationBuilder DocumentationBuilder {
196 public Evaluator Evaluator {
200 public bool HasDefaultCharSet {
202 return DefaultCharSet.HasValue;
206 public bool HasExtensionMethod {
208 return has_extenstion_method;
211 has_extenstion_method = value;
215 public bool HasTypesFullyDefined {
220 // Returns module global:: namespace
222 public RootNamespace GlobalRootNamespace {
228 public override ModuleContainer Module {
234 internal Dictionary<TypeSpec, PointerContainer> PointerTypesCache {
236 return pointer_types;
240 internal PredefinedAttributes PredefinedAttributes {
242 return predefined_attributes;
246 internal PredefinedMembers PredefinedMembers {
248 return predefined_members;
252 internal PredefinedTypes PredefinedTypes {
254 return predefined_types;
258 internal Dictionary<TypeSpec, ReferenceContainer> ReferenceTypesCache {
260 return reference_types;
264 public override string[] ValidAttributeTargets {
266 return attribute_targets;
272 public override void Accept (StructuralVisitor visitor)
274 visitor.Visit (this);
277 public void AddAnonymousType (AnonymousTypeClass type)
279 List<AnonymousTypeClass> existing;
280 if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing))
281 if (existing == null) {
282 existing = new List<AnonymousTypeClass> ();
283 anonymous_types.Add (type.Parameters.Count, existing);
289 public void AddAttribute (Attribute attr, IMemberContext context)
291 attr.AttachTo (this, context);
293 if (attributes == null) {
294 attributes = new Attributes (attr);
298 attributes.AddAttribute (attr);
301 public override TypeContainer AddPartial (TypeContainer nextPart)
303 return AddPartial (nextPart, nextPart.Name);
306 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
308 if (a.Target == AttributeTargets.Assembly) {
309 assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
313 if (a.Type == pa.DefaultCharset) {
314 switch (a.GetCharSetValue ()) {
319 DefaultCharSet = CharSet.Auto;
320 DefaultCharSetType = TypeAttributes.AutoClass;
322 case CharSet.Unicode:
323 DefaultCharSet = CharSet.Unicode;
324 DefaultCharSetType = TypeAttributes.UnicodeClass;
327 Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid",
328 a.GetSignatureForError ());
331 } else if (a.Type == pa.CLSCompliant) {
332 Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
334 Report.Warning (3012, 1, a.Location,
335 "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
336 } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) {
337 Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ());
338 Report.Warning (3017, 1, a.Location,
339 "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
344 builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
347 public override void CloseType ()
349 foreach (TypeContainer tc in types) {
353 if (compiler_generated != null)
354 foreach (CompilerGeneratedClass c in compiler_generated)
358 public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
360 return builder.DefineType (name, attr, null, typeSize);
364 // Creates alias global namespace
366 public RootNamespace CreateRootNamespace (string alias)
368 if (alias == global_ns.Alias) {
369 NamespaceContainer.Error_GlobalNamespaceRedefined (Location.Null, Report);
374 if (!alias_ns.TryGetValue (alias, out rn)) {
375 rn = new RootNamespace (alias);
376 alias_ns.Add (alias, rn);
382 public void Create (AssemblyDefinition assembly, ModuleBuilder moduleBuilder)
384 this.assembly = assembly;
385 builder = moduleBuilder;
388 public new void CreateType ()
390 // Release cache used by parser only
391 if (Evaluator == null)
392 defined_type_containers = null;
394 defined_type_containers.Clear ();
396 foreach (TypeContainer tc in types)
400 public new void Define ()
402 foreach (TypeContainer tc in types)
405 foreach (TypeContainer tc in types)
406 tc.ResolveTypeParameters ();
408 foreach (TypeContainer tc in types) {
411 } catch (Exception e) {
412 throw new InternalErrorException (tc, e);
416 HasTypesFullyDefined = true;
419 public override void Emit ()
421 if (OptAttributes != null)
422 OptAttributes.Emit ();
424 if (Compiler.Settings.Unsafe) {
425 var pa = PredefinedAttributes.UnverifiableCode;
427 pa.EmitAttribute (builder);
430 foreach (var tc in types)
431 tc.DefineConstants ();
433 foreach (TypeContainer tc in types)
436 if (Compiler.Report.Errors > 0)
439 foreach (TypeContainer tc in types)
442 if (compiler_generated != null)
443 foreach (var c in compiler_generated)
447 internal override void GenerateDocComment (DocumentationBuilder builder)
449 foreach (var tc in types)
450 tc.GenerateDocComment (builder);
453 public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
455 List<AnonymousTypeClass> candidates;
456 if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
460 foreach (AnonymousTypeClass at in candidates) {
461 for (i = 0; i < parameters.Count; ++i) {
462 if (!parameters [i].Equals (at.Parameters [i]))
466 if (i == parameters.Count)
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 protected override bool AddMemberType (TypeContainer tc)
499 if (AddTypesContainer (tc)) {
500 if ((tc.ModFlags & Modifiers.PARTIAL) != 0)
501 defined_names.Add (tc.Name, tc);
503 tc.NamespaceEntry.NS.AddType (this, tc.Definition);
510 public bool AddTypesContainer (ITypesContainer container)
512 var mn = container.MemberName;
513 ITypesContainer found;
514 if (!defined_type_containers.TryGetValue (mn, out found)) {
515 defined_type_containers.Add (mn, container);
519 if (container is NamespaceContainer && found is NamespaceContainer)
522 var container_tc = container as TypeContainer;
523 var found_tc = found as TypeContainer;
524 if (container_tc != null && found_tc != null && container_tc.Kind == found_tc.Kind) {
525 if ((found_tc.ModFlags & container_tc.ModFlags & Modifiers.PARTIAL) != 0) {
529 if (((found_tc.ModFlags | container_tc.ModFlags) & Modifiers.PARTIAL) != 0) {
530 Report.SymbolRelatedToPreviousError (found_tc);
531 Error_MissingPartialModifier (container_tc);
536 string ns = mn.Left != null ? mn.Left.GetSignatureForError () : Module.GlobalRootNamespace.GetSignatureForError ();
537 mn = new MemberName (mn.Name, mn.TypeArguments, mn.Location);
539 Report.SymbolRelatedToPreviousError (found.Location, "");
540 Report.Error (101, container.Location,
541 "The namespace `{0}' already contains a definition for `{1}'",
542 ns, mn.GetSignatureForError ());
546 protected override void RemoveMemberType (TypeContainer ds)
548 defined_type_containers.Remove (ds.MemberName);
549 ds.NamespaceEntry.NS.RemoveDeclSpace (ds.Basename);
550 base.RemoveMemberType (ds);
553 public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
555 Attribute a = OptAttributes.Search ("assembly", a_type);
562 public void SetDeclaringAssembly (AssemblyDefinition assembly)
564 // TODO: This setter is quite ugly but I have not found a way around it yet
565 this.assembly = assembly;
569 sealed class RootDeclSpace : TypeContainer {
570 public RootDeclSpace (ModuleContainer module, NamespaceContainer ns)
571 : base (ns, null, MemberName.Null, null, 0)
573 PartialContainer = module;
576 public override AttributeTargets AttributeTargets {
577 get { throw new InternalErrorException ("should not be called"); }
580 public override CompilerContext Compiler {
582 return PartialContainer.Compiler;
586 public override string DocCommentHeader {
587 get { throw new InternalErrorException ("should not be called"); }
590 public override void DefineType ()
592 throw new InternalErrorException ("should not be called");
595 public override ModuleContainer Module {
597 return PartialContainer.Module;
601 public override void Accept (StructuralVisitor visitor)
603 throw new InternalErrorException ("should not be called");
606 public override bool IsClsComplianceRequired ()
608 return PartialContainer.IsClsComplianceRequired ();
611 public override ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
616 public override FullNamedExpression LookupNamespaceAlias (string name)
618 return NamespaceEntry.LookupNamespaceAlias (name);