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 : CompilerGeneratedContainer
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),
46 Modifiers.STATIC | Modifiers.INTERNAL)
48 size_types = new Dictionary<int, Struct> ();
51 public override void CloseContainer ()
53 base.CloseContainer ();
55 foreach (var entry in size_types) {
56 entry.Value.CloseContainer ();
60 public FieldSpec DefineInitializedData (byte[] data, Location loc)
63 if (!size_types.TryGetValue (data.Length, out size_type)) {
65 // Build common type for this data length. We cannot use
66 // DefineInitializedData because it creates public type,
67 // and its name is not unique among modules
69 size_type = new Struct (this, new MemberName ("$ArrayType=" + data.Length, loc), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, null);
70 size_type.CreateContainer ();
71 size_type.DefineContainer ();
73 size_types.Add (data.Length, size_type);
75 // It has to work even if StructLayoutAttribute does not exist
76 size_type.TypeBuilder.__SetLayout (1, data.Length);
79 var name = "$field-" + fields.ToString ("X");
81 const Modifiers fmod = Modifiers.STATIC | Modifiers.INTERNAL;
82 var fbuilder = TypeBuilder.DefineField (name, size_type.CurrentType.GetMetaInfo (), ModifiersExtensions.FieldAttr (fmod) | FieldAttributes.HasFieldRVA);
83 fbuilder.__SetDataAndRVA (data);
85 return new FieldSpec (CurrentType, null, size_type.CurrentType, fbuilder, fmod);
89 StaticDataContainer static_data;
92 // Makes const data field inside internal type container
94 public FieldSpec MakeStaticData (byte[] data, Location loc)
96 if (static_data == null) {
97 static_data = new StaticDataContainer (this);
98 static_data.CreateContainer ();
99 static_data.DefineContainer ();
101 AddCompilerGeneratedClass (static_data);
104 return static_data.DefineInitializedData (data, loc);
108 public sealed class PatternMatchingHelper : CompilerGeneratedContainer
110 public PatternMatchingHelper (ModuleContainer module)
111 : base (module, new MemberName ("<PatternMatchingHelper>", Location.Null),
112 Modifiers.STATIC | Modifiers.INTERNAL | Modifiers.DEBUGGER_HIDDEN)
116 public Method NumberMatcher { get; private set; }
118 protected override bool DoDefineMembers ()
120 if (!base.DoDefineMembers ())
123 NumberMatcher = GenerateNumberMatcher ();
127 Method GenerateNumberMatcher ()
130 var parameters = ParametersCompiled.CreateFullyResolved (
132 new Parameter (new TypeExpression (Compiler.BuiltinTypes.Object, loc), "obj", 0, null, loc),
133 new Parameter (new TypeExpression (Compiler.BuiltinTypes.Object, loc), "value", 0, null, loc),
134 new Parameter (new TypeExpression (Compiler.BuiltinTypes.Bool, loc), "enumType", 0, null, loc),
137 Compiler.BuiltinTypes.Object,
138 Compiler.BuiltinTypes.Object,
139 Compiler.BuiltinTypes.Bool
142 var m = new Method (this, new TypeExpression (Compiler.BuiltinTypes.Bool, loc),
143 Modifiers.PUBLIC | Modifiers.STATIC | Modifiers.DEBUGGER_HIDDEN, new MemberName ("NumberMatcher", loc),
146 parameters [0].Resolve (m, 0);
147 parameters [1].Resolve (m, 1);
148 parameters [2].Resolve (m, 2);
150 ToplevelBlock top_block = new ToplevelBlock (Compiler, parameters, loc);
155 // return Equals (obj, value);
157 var equals_args = new Arguments (2);
158 equals_args.Add (new Argument (top_block.GetParameterReference (0, loc)));
159 equals_args.Add (new Argument (top_block.GetParameterReference (1, loc)));
161 var if_type = new If (
162 top_block.GetParameterReference (2, loc),
163 new Return (new Invocation (new SimpleName ("Equals", loc), equals_args), loc),
166 top_block.AddStatement (if_type);
169 // if (obj is Enum || obj == null)
173 var if_enum = new If (
174 new Binary (Binary.Operator.LogicalOr,
175 new Is (top_block.GetParameterReference (0, loc), new TypeExpression (Compiler.BuiltinTypes.Enum, loc), loc),
176 new Binary (Binary.Operator.Equality, top_block.GetParameterReference (0, loc), new NullLiteral (loc))),
177 new Return (new BoolLiteral (Compiler.BuiltinTypes, false, loc), loc),
180 top_block.AddStatement (if_enum);
183 var system_convert = new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "Convert", loc);
186 // var converted = System.Convert.ChangeType (obj, System.Convert.GetTypeCode (value));
188 var lv_converted = LocalVariable.CreateCompilerGenerated (Compiler.BuiltinTypes.Object, top_block, loc);
190 var arguments_gettypecode = new Arguments (1);
191 arguments_gettypecode.Add (new Argument (top_block.GetParameterReference (1, loc)));
193 var gettypecode = new Invocation (new MemberAccess (system_convert, "GetTypeCode", loc), arguments_gettypecode);
195 var arguments_changetype = new Arguments (1);
196 arguments_changetype.Add (new Argument (top_block.GetParameterReference (0, loc)));
197 arguments_changetype.Add (new Argument (gettypecode));
199 var changetype = new Invocation (new MemberAccess (system_convert, "ChangeType", loc), arguments_changetype);
201 top_block.AddStatement (new StatementExpression (new SimpleAssign (new LocalVariableReference (lv_converted, loc), changetype, loc)));
205 // return converted.Equals (value)
207 var equals_arguments = new Arguments (1);
208 equals_arguments.Add (new Argument (top_block.GetParameterReference (1, loc)));
209 var equals_invocation = new Invocation (new MemberAccess (new LocalVariableReference (lv_converted, loc), "Equals"), equals_arguments);
210 top_block.AddStatement (new Return (equals_invocation, loc));
220 PatternMatchingHelper pmh;
222 public PatternMatchingHelper CreatePatterMatchingHelper ()
225 pmh = new PatternMatchingHelper (this);
227 pmh.CreateContainer ();
228 pmh.DefineContainer ();
230 AddCompilerGeneratedClass (pmh);
236 public CharSet? DefaultCharSet;
237 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
239 readonly Dictionary<int, List<AnonymousTypeClass>> anonymous_types;
240 readonly Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> array_types;
241 readonly Dictionary<TypeSpec, PointerContainer> pointer_types;
242 readonly Dictionary<TypeSpec, ReferenceContainer> reference_types;
243 readonly Dictionary<TypeSpec, MethodSpec> attrs_cache;
244 readonly Dictionary<TypeSpec, AwaiterDefinition> awaiters;
246 AssemblyDefinition assembly;
247 readonly CompilerContext context;
248 readonly RootNamespace global_ns;
249 readonly Dictionary<string, RootNamespace> alias_ns;
251 ModuleBuilder builder;
253 bool has_extenstion_method;
255 PredefinedAttributes predefined_attributes;
256 PredefinedTypes predefined_types;
257 PredefinedMembers predefined_members;
259 public Binary.PredefinedOperator[] OperatorsBinaryEqualityLifted;
260 public Binary.PredefinedOperator[] OperatorsBinaryLifted;
262 static readonly string[] attribute_targets = new string[] { "assembly", "module" };
264 public ModuleContainer (CompilerContext context)
265 : base (null, MemberName.Null, null, 0)
267 this.context = context;
269 caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected);
271 containers = new List<TypeContainer> ();
272 anonymous_types = new Dictionary<int, List<AnonymousTypeClass>> ();
273 global_ns = new GlobalRootNamespace ();
274 alias_ns = new Dictionary<string, RootNamespace> ();
275 array_types = new Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ();
276 pointer_types = new Dictionary<TypeSpec, PointerContainer> ();
277 reference_types = new Dictionary<TypeSpec, ReferenceContainer> ();
278 attrs_cache = new Dictionary<TypeSpec, MethodSpec> ();
279 awaiters = new Dictionary<TypeSpec, AwaiterDefinition> ();
284 internal Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ArrayTypesCache {
291 // Cache for parameter-less attributes
293 internal Dictionary<TypeSpec, MethodSpec> AttributeConstructorCache {
299 public override AttributeTargets AttributeTargets {
301 return AttributeTargets.Assembly;
305 public ModuleBuilder Builder {
311 public override CompilerContext Compiler {
317 public int CounterAnonymousTypes { get; set; }
319 public AssemblyDefinition DeclaringAssembly {
325 internal DocumentationBuilder DocumentationBuilder {
329 public override string DocCommentHeader {
331 throw new NotSupportedException ();
335 public Evaluator Evaluator {
339 public bool HasDefaultCharSet {
341 return DefaultCharSet.HasValue;
345 public bool HasExtensionMethod {
347 return has_extenstion_method;
350 has_extenstion_method = value;
354 public bool HasTypesFullyDefined {
359 // Returns module global:: namespace
361 public RootNamespace GlobalRootNamespace {
367 public override ModuleContainer Module {
373 internal Dictionary<TypeSpec, PointerContainer> PointerTypesCache {
375 return pointer_types;
379 internal PredefinedAttributes PredefinedAttributes {
381 return predefined_attributes;
385 internal PredefinedMembers PredefinedMembers {
387 return predefined_members;
391 internal PredefinedTypes PredefinedTypes {
393 return predefined_types;
397 internal Dictionary<TypeSpec, ReferenceContainer> ReferenceTypesCache {
399 return reference_types;
403 public override string[] ValidAttributeTargets {
405 return attribute_targets;
411 public override void Accept (StructuralVisitor visitor)
413 visitor.Visit (this);
416 public void AddAnonymousType (AnonymousTypeClass type)
418 List<AnonymousTypeClass> existing;
419 if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing))
420 if (existing == null) {
421 existing = new List<AnonymousTypeClass> ();
422 anonymous_types.Add (type.Parameters.Count, existing);
428 public void AddAttribute (Attribute attr, IMemberContext context)
430 attr.AttachTo (this, context);
432 if (attributes == null) {
433 attributes = new Attributes (attr);
437 attributes.AddAttribute (attr);
440 public override void AddTypeContainer (TypeContainer tc)
442 AddTypeContainerMember (tc);
445 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
447 if (a.Target == AttributeTargets.Assembly) {
448 assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
452 if (a.Type == pa.DefaultCharset) {
453 switch (a.GetCharSetValue ()) {
458 DefaultCharSet = CharSet.Auto;
459 DefaultCharSetType = TypeAttributes.AutoClass;
461 case CharSet.Unicode:
462 DefaultCharSet = CharSet.Unicode;
463 DefaultCharSetType = TypeAttributes.UnicodeClass;
466 Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid",
467 a.GetSignatureForError ());
470 } else if (a.Type == pa.CLSCompliant) {
471 Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
473 Report.Warning (3012, 1, a.Location,
474 "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
475 } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) {
476 Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ());
477 Report.Warning (3017, 1, a.Location,
478 "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
483 builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
486 public override void CloseContainer ()
488 if (anonymous_types != null) {
489 foreach (var atypes in anonymous_types)
490 foreach (var at in atypes.Value)
491 at.CloseContainer ();
494 base.CloseContainer ();
497 public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
499 return builder.DefineType (name, attr, null, typeSize);
503 // Creates alias global namespace
505 public RootNamespace CreateRootNamespace (string alias)
507 if (alias == global_ns.Alias) {
508 RootNamespace.Error_GlobalNamespaceRedefined (Report, Location.Null);
513 if (!alias_ns.TryGetValue (alias, out rn)) {
514 rn = new RootNamespace (alias);
515 alias_ns.Add (alias, rn);
521 public void Create (AssemblyDefinition assembly, ModuleBuilder moduleBuilder)
523 this.assembly = assembly;
524 builder = moduleBuilder;
527 public override bool Define ()
531 ExpandBaseInterfaces ();
535 HasTypesFullyDefined = true;
540 public override bool DefineContainer ()
544 return base.DefineContainer ();
547 public void EnableRedefinition ()
552 public override void EmitContainer ()
554 if (OptAttributes != null)
555 OptAttributes.Emit ();
557 if (Compiler.Settings.Unsafe && !assembly.IsSatelliteAssembly) {
558 var pa = PredefinedAttributes.UnverifiableCode;
560 pa.EmitAttribute (builder);
563 foreach (var tc in containers) {
567 base.EmitContainer ();
569 if (Compiler.Report.Errors == 0 && !Compiler.Settings.WriteMetadataOnly)
572 if (anonymous_types != null) {
573 foreach (var atypes in anonymous_types)
574 foreach (var at in atypes.Value)
579 internal override void GenerateDocComment (DocumentationBuilder builder)
581 foreach (var tc in containers)
582 tc.GenerateDocComment (builder);
585 public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
587 List<AnonymousTypeClass> candidates;
588 if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
592 foreach (AnonymousTypeClass at in candidates) {
593 for (i = 0; i < parameters.Count; ++i) {
594 if (!parameters [i].Equals (at.Parameters [i]))
598 if (i == parameters.Count)
606 // Return container with awaiter definition. It never returns null
607 // but all container member can be null for easier error reporting
609 public AwaiterDefinition GetAwaiter (TypeSpec type)
611 AwaiterDefinition awaiter;
612 if (awaiters.TryGetValue (type, out awaiter))
615 awaiter = new AwaiterDefinition ();
618 // Predefined: bool IsCompleted { get; }
620 awaiter.IsCompleted = MemberCache.FindMember (type, MemberFilter.Property ("IsCompleted", Compiler.BuiltinTypes.Bool),
621 BindingRestriction.InstanceOnly) as PropertySpec;
624 // Predefined: GetResult ()
626 // The method return type is also result type of await expression
628 awaiter.GetResult = MemberCache.FindMember (type, MemberFilter.Method ("GetResult", 0,
629 ParametersCompiled.EmptyReadOnlyParameters, null),
630 BindingRestriction.InstanceOnly) as MethodSpec;
633 // Predefined: INotifyCompletion.OnCompleted (System.Action)
635 var nc = PredefinedTypes.INotifyCompletion;
636 awaiter.INotifyCompletion = !nc.Define () || type.ImplementsInterface (nc.TypeSpec, false);
638 awaiters.Add (type, awaiter);
642 public override void GetCompletionStartingWith (string prefix, List<string> results)
644 var names = Evaluator.GetVarNames ();
645 results.AddRange (names.Where (l => l.StartsWith (prefix)));
648 public RootNamespace GetRootNamespace (string name)
651 alias_ns.TryGetValue (name, out rn);
655 public override string GetSignatureForError ()
660 public Binary.PredefinedOperator[] GetPredefinedEnumAritmeticOperators (TypeSpec enumType, bool nullable)
663 Binary.Operator mask = 0;
666 underlying = Nullable.NullableInfo.GetEnumUnderlyingType (this, enumType);
667 mask = Binary.Operator.NullableMask;
669 underlying = EnumSpec.GetUnderlyingType (enumType);
672 var operators = new[] {
673 new Binary.PredefinedOperator (enumType, underlying,
674 mask | Binary.Operator.AdditionMask | Binary.Operator.SubtractionMask | Binary.Operator.DecomposedMask, enumType),
675 new Binary.PredefinedOperator (underlying, enumType,
676 mask | Binary.Operator.AdditionMask | Binary.Operator.SubtractionMask | Binary.Operator.DecomposedMask, enumType),
677 new Binary.PredefinedOperator (enumType, mask | Binary.Operator.SubtractionMask, underlying)
683 public void InitializePredefinedTypes ()
685 predefined_attributes = new PredefinedAttributes (this);
686 predefined_types = new PredefinedTypes (this);
687 predefined_members = new PredefinedMembers (this);
689 OperatorsBinaryEqualityLifted = Binary.CreateEqualityLiftedOperatorsTable (this);
690 OperatorsBinaryLifted = Binary.CreateStandardLiftedOperatorsTable (this);
693 public override bool IsClsComplianceRequired ()
695 return DeclaringAssembly.IsCLSCompliant;
698 public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
700 Attribute a = OptAttributes.Search ("assembly", a_type);
707 public void SetDeclaringAssembly (AssemblyDefinition assembly)
709 // TODO: This setter is quite ugly but I have not found a way around it yet
710 this.assembly = assembly;