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.
11 // Copyright 2011 Xamarin Inc
15 using System.Collections.Generic;
16 using System.Runtime.InteropServices;
17 using Mono.CompilerServices.SymbolWriter;
20 using IKVM.Reflection;
21 using IKVM.Reflection.Emit;
23 using System.Reflection;
24 using System.Reflection.Emit;
30 // Module (top-level type) container
32 public sealed class ModuleContainer : TypeContainer
36 // Compiler generated container for static data
38 sealed class StaticDataContainer : CompilerGeneratedClass
40 readonly Dictionary<int, Struct> size_types;
43 public StaticDataContainer (ModuleContainer module)
44 : base (module, new MemberName ("<PrivateImplementationDetails>" + module.builder.ModuleVersionId.ToString ("B"), Location.Null), Modifiers.STATIC)
46 size_types = new Dictionary<int, Struct> ();
49 public override void CloseType ()
53 foreach (var entry in size_types) {
54 entry.Value.CloseType ();
58 public FieldSpec DefineInitializedData (byte[] data, Location loc)
61 if (!size_types.TryGetValue (data.Length, out size_type)) {
63 // Build common type for this data length. We cannot use
64 // DefineInitializedData because it creates public type,
65 // and its name is not unique among modules
67 size_type = new Struct (null, this, new MemberName ("$ArrayType=" + data.Length, loc), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, null);
68 size_type.CreateType ();
69 size_type.DefineType ();
71 size_types.Add (data.Length, size_type);
73 // It has to work even if StructLayoutAttribute does not exist
74 size_type.TypeBuilder.__SetLayout (1, data.Length);
77 var name = "$field-" + fields.ToString ("X");
79 const Modifiers fmod = Modifiers.STATIC | Modifiers.INTERNAL;
80 var fbuilder = TypeBuilder.DefineField (name, size_type.CurrentType.GetMetaInfo (), ModifiersExtensions.FieldAttr (fmod) | FieldAttributes.HasFieldRVA);
81 fbuilder.__SetDataAndRVA (data);
83 return new FieldSpec (CurrentType, null, size_type.CurrentType, fbuilder, fmod);
87 StaticDataContainer static_data;
90 // Makes const data field inside internal type container
92 public FieldSpec MakeStaticData (byte[] data, Location loc)
94 if (static_data == null) {
95 static_data = new StaticDataContainer (this);
96 static_data.CreateType ();
97 static_data.DefineType ();
99 AddCompilerGeneratedClass (static_data);
102 return static_data.DefineInitializedData (data, loc);
106 public CharSet? DefaultCharSet;
107 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
109 readonly Dictionary<int, List<AnonymousTypeClass>> anonymous_types;
110 readonly Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> array_types;
111 readonly Dictionary<TypeSpec, PointerContainer> pointer_types;
112 readonly Dictionary<TypeSpec, ReferenceContainer> reference_types;
113 readonly Dictionary<TypeSpec, MethodSpec> attrs_cache;
115 // Used for unique namespaces/types during parsing
116 Dictionary<MemberName, ITypesContainer> defined_type_containers;
118 AssemblyDefinition assembly;
119 readonly CompilerContext context;
120 readonly RootNamespace global_ns;
121 readonly Dictionary<string, RootNamespace> alias_ns;
123 ModuleBuilder builder;
125 bool has_extenstion_method;
127 PredefinedAttributes predefined_attributes;
128 PredefinedTypes predefined_types;
129 PredefinedMembers predefined_members;
131 static readonly string[] attribute_targets = new string[] { "assembly", "module" };
133 public ModuleContainer (CompilerContext context)
134 : base (null, null, MemberName.Null, null, 0)
136 this.context = context;
138 caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected);
140 types = new List<TypeContainer> ();
141 anonymous_types = new Dictionary<int, List<AnonymousTypeClass>> ();
142 global_ns = new GlobalRootNamespace ();
143 alias_ns = new Dictionary<string, RootNamespace> ();
144 array_types = new Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ();
145 pointer_types = new Dictionary<TypeSpec, PointerContainer> ();
146 reference_types = new Dictionary<TypeSpec, ReferenceContainer> ();
147 attrs_cache = new Dictionary<TypeSpec, MethodSpec> ();
149 defined_type_containers = new Dictionary<MemberName, ITypesContainer> ();
154 internal Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ArrayTypesCache {
161 // Cache for parameter-less attributes
163 internal Dictionary<TypeSpec, MethodSpec> AttributeConstructorCache {
169 public override AttributeTargets AttributeTargets {
171 return AttributeTargets.Assembly;
175 public ModuleBuilder Builder {
181 public override CompilerContext Compiler {
187 public override AssemblyDefinition DeclaringAssembly {
193 internal DocumentationBuilder DocumentationBuilder {
197 public Evaluator Evaluator {
201 public bool HasDefaultCharSet {
203 return DefaultCharSet.HasValue;
207 public bool HasExtensionMethod {
209 return has_extenstion_method;
212 has_extenstion_method = value;
216 public bool HasTypesFullyDefined {
221 // Returns module global:: namespace
223 public RootNamespace GlobalRootNamespace {
229 public override ModuleContainer Module {
235 internal Dictionary<TypeSpec, PointerContainer> PointerTypesCache {
237 return pointer_types;
241 internal PredefinedAttributes PredefinedAttributes {
243 return predefined_attributes;
247 internal PredefinedMembers PredefinedMembers {
249 return predefined_members;
253 internal PredefinedTypes PredefinedTypes {
255 return predefined_types;
259 internal Dictionary<TypeSpec, ReferenceContainer> ReferenceTypesCache {
261 return reference_types;
265 public override string[] ValidAttributeTargets {
267 return attribute_targets;
273 public override void Accept (StructuralVisitor visitor)
275 visitor.Visit (this);
278 public void AddAnonymousType (AnonymousTypeClass type)
280 List<AnonymousTypeClass> existing;
281 if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing))
282 if (existing == null) {
283 existing = new List<AnonymousTypeClass> ();
284 anonymous_types.Add (type.Parameters.Count, existing);
290 public void AddAttribute (Attribute attr, IMemberContext context)
292 attr.AttachTo (this, context);
294 if (attributes == null) {
295 attributes = new Attributes (attr);
299 attributes.AddAttribute (attr);
302 public override TypeContainer AddPartial (TypeContainer nextPart)
304 return AddPartial (nextPart, nextPart.Name);
307 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
309 if (a.Target == AttributeTargets.Assembly) {
310 assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
314 if (a.Type == pa.DefaultCharset) {
315 switch (a.GetCharSetValue ()) {
320 DefaultCharSet = CharSet.Auto;
321 DefaultCharSetType = TypeAttributes.AutoClass;
323 case CharSet.Unicode:
324 DefaultCharSet = CharSet.Unicode;
325 DefaultCharSetType = TypeAttributes.UnicodeClass;
328 Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid",
329 a.GetSignatureForError ());
332 } else if (a.Type == pa.CLSCompliant) {
333 Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
335 Report.Warning (3012, 1, a.Location,
336 "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
337 } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) {
338 Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ());
339 Report.Warning (3017, 1, a.Location,
340 "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
345 builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
348 public override void CloseType ()
350 foreach (TypeContainer tc in types) {
354 if (compiler_generated != null)
355 foreach (CompilerGeneratedClass c in compiler_generated)
359 public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
361 return builder.DefineType (name, attr, null, typeSize);
365 // Creates alias global namespace
367 public RootNamespace CreateRootNamespace (string alias)
369 if (alias == global_ns.Alias) {
370 NamespaceContainer.Error_GlobalNamespaceRedefined (Location.Null, Report);
375 if (!alias_ns.TryGetValue (alias, out rn)) {
376 rn = new RootNamespace (alias);
377 alias_ns.Add (alias, rn);
383 public void Create (AssemblyDefinition assembly, ModuleBuilder moduleBuilder)
385 this.assembly = assembly;
386 builder = moduleBuilder;
389 public new void CreateType ()
391 // Release cache used by parser only
392 if (Evaluator == null)
393 defined_type_containers = null;
395 defined_type_containers.Clear ();
397 foreach (TypeContainer tc in types)
401 public new void Define ()
403 foreach (TypeContainer tc in types) {
406 } catch (Exception e) {
407 throw new InternalErrorException (tc, e);
411 foreach (TypeContainer tc in types)
412 tc.ResolveTypeParameters ();
414 foreach (TypeContainer tc in types) {
417 } catch (Exception e) {
418 throw new InternalErrorException (tc, e);
422 HasTypesFullyDefined = true;
425 public override void Emit ()
427 if (OptAttributes != null)
428 OptAttributes.Emit ();
430 if (Compiler.Settings.Unsafe) {
431 var pa = PredefinedAttributes.UnverifiableCode;
433 pa.EmitAttribute (builder);
436 foreach (var tc in types)
437 tc.DefineConstants ();
439 foreach (TypeContainer tc in types)
442 if (Compiler.Report.Errors > 0)
445 foreach (TypeContainer tc in types)
448 if (compiler_generated != null)
449 foreach (var c in compiler_generated)
453 internal override void GenerateDocComment (DocumentationBuilder builder)
455 foreach (var tc in types)
456 tc.GenerateDocComment (builder);
459 public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
461 List<AnonymousTypeClass> candidates;
462 if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
466 foreach (AnonymousTypeClass at in candidates) {
467 for (i = 0; i < parameters.Count; ++i) {
468 if (!parameters [i].Equals (at.Parameters [i]))
472 if (i == parameters.Count)
479 public RootNamespace GetRootNamespace (string name)
482 alias_ns.TryGetValue (name, out rn);
486 public override string GetSignatureForError ()
491 public void InitializePredefinedTypes ()
493 predefined_attributes = new PredefinedAttributes (this);
494 predefined_types = new PredefinedTypes (this);
495 predefined_members = new PredefinedMembers (this);
498 public override bool IsClsComplianceRequired ()
500 return DeclaringAssembly.IsCLSCompliant;
503 protected override bool AddMemberType (TypeContainer tc)
505 if (AddTypesContainer (tc)) {
506 if ((tc.ModFlags & Modifiers.PARTIAL) != 0)
507 defined_names.Add (tc.Name, tc);
509 tc.NamespaceEntry.NS.AddType (this, tc.Definition);
516 public bool AddTypesContainer (ITypesContainer container)
518 var mn = container.MemberName;
519 ITypesContainer found;
520 if (!defined_type_containers.TryGetValue (mn, out found)) {
521 defined_type_containers.Add (mn, container);
525 if (container is NamespaceContainer && found is NamespaceContainer)
528 var container_tc = container as TypeContainer;
529 var found_tc = found as TypeContainer;
530 if (container_tc != null && found_tc != null && container_tc.Kind == found_tc.Kind) {
531 if ((found_tc.ModFlags & container_tc.ModFlags & Modifiers.PARTIAL) != 0) {
535 if (((found_tc.ModFlags | container_tc.ModFlags) & Modifiers.PARTIAL) != 0) {
536 Report.SymbolRelatedToPreviousError (found_tc);
537 Error_MissingPartialModifier (container_tc);
542 string ns = mn.Left != null ? mn.Left.GetSignatureForError () : Module.GlobalRootNamespace.GetSignatureForError ();
543 mn = new MemberName (mn.Name, mn.TypeArguments, mn.Location);
545 Report.SymbolRelatedToPreviousError (found.Location, "");
546 Report.Error (101, container.Location,
547 "The namespace `{0}' already contains a definition for `{1}'",
548 ns, mn.GetSignatureForError ());
552 protected override void RemoveMemberType (TypeContainer ds)
554 defined_type_containers.Remove (ds.MemberName);
555 ds.NamespaceEntry.NS.RemoveDeclSpace (ds.Basename);
556 base.RemoveMemberType (ds);
559 public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
561 Attribute a = OptAttributes.Search ("assembly", a_type);
568 public void SetDeclaringAssembly (AssemblyDefinition assembly)
570 // TODO: This setter is quite ugly but I have not found a way around it yet
571 this.assembly = assembly;
575 sealed class RootDeclSpace : TypeContainer {
576 public RootDeclSpace (ModuleContainer module, NamespaceContainer ns)
577 : base (ns, null, MemberName.Null, null, 0)
579 PartialContainer = module;
582 public override AttributeTargets AttributeTargets {
583 get { throw new InternalErrorException ("should not be called"); }
586 public override CompilerContext Compiler {
588 return PartialContainer.Compiler;
592 public override string DocCommentHeader {
593 get { throw new InternalErrorException ("should not be called"); }
596 public override void DefineType ()
598 throw new InternalErrorException ("should not be called");
601 public override ModuleContainer Module {
603 return PartialContainer.Module;
607 public override void Accept (StructuralVisitor visitor)
609 throw new InternalErrorException ("should not be called");
612 public override bool IsClsComplianceRequired ()
614 return PartialContainer.IsClsComplianceRequired ();
617 public override ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
622 public override FullNamedExpression LookupNamespaceAlias (string name)
624 return NamespaceEntry.LookupNamespaceAlias (name);