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 CharSet? DefaultCharSet;
109
public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
111
readonly Dictionary<int, List<AnonymousTypeClass>> anonymous_types;
112
readonly Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> array_types;
113
readonly Dictionary<TypeSpec, PointerContainer> pointer_types;
114
readonly Dictionary<TypeSpec, ReferenceContainer> reference_types;
115
readonly Dictionary<TypeSpec, MethodSpec> attrs_cache;
116
readonly Dictionary<TypeSpec, AwaiterDefinition> awaiters;
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, MemberName.Null, null, 0)
136
this.context = context;
138
caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected);
140
containers = 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> ();
148
awaiters = new Dictionary<TypeSpec, AwaiterDefinition> ();
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 int CounterAnonymousTypes { get; set; }
187
public int CounterAnonymousMethods { get; set; }
188
public int CounterAnonymousContainers { get; set; }
189
public int CounterSwitchTypes { get; set; }
191
public AssemblyDefinition DeclaringAssembly {
197
internal DocumentationBuilder DocumentationBuilder {
201
public override string DocCommentHeader {
203
throw new NotSupportedException ();
207
public Evaluator Evaluator {
211
public bool HasDefaultCharSet {
213
return DefaultCharSet.HasValue;
217
public bool HasExtensionMethod {
219
return has_extenstion_method;
222
has_extenstion_method = value;
226
public bool HasTypesFullyDefined {
231
// Returns module global:: namespace
233
public RootNamespace GlobalRootNamespace {
239
public override ModuleContainer Module {
245
internal Dictionary<TypeSpec, PointerContainer> PointerTypesCache {
247
return pointer_types;
251
internal PredefinedAttributes PredefinedAttributes {
253
return predefined_attributes;
257
internal PredefinedMembers PredefinedMembers {
259
return predefined_members;
263
internal PredefinedTypes PredefinedTypes {
265
return predefined_types;
269
internal Dictionary<TypeSpec, ReferenceContainer> ReferenceTypesCache {
271
return reference_types;
275
public override string[] ValidAttributeTargets {
277
return attribute_targets;
283
public override void Accept (StructuralVisitor visitor)
285
visitor.Visit (this);
288
public void AddAnonymousType (AnonymousTypeClass type)
290
List<AnonymousTypeClass> existing;
291
if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing))
292
if (existing == null) {
293
existing = new List<AnonymousTypeClass> ();
294
anonymous_types.Add (type.Parameters.Count, existing);
300
public void AddAttribute (Attribute attr, IMemberContext context)
302
attr.AttachTo (this, context);
304
if (attributes == null) {
305
attributes = new Attributes (attr);
309
attributes.AddAttribute (attr);
312
public override void AddTypeContainer (TypeContainer tc)
317
public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
319
if (a.Target == AttributeTargets.Assembly) {
320
assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
324
if (a.Type == pa.DefaultCharset) {
325
switch (a.GetCharSetValue ()) {
330
DefaultCharSet = CharSet.Auto;
331
DefaultCharSetType = TypeAttributes.AutoClass;
333
case CharSet.Unicode:
334
DefaultCharSet = CharSet.Unicode;
335
DefaultCharSetType = TypeAttributes.UnicodeClass;
338
Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid",
339
a.GetSignatureForError ());
342
} else if (a.Type == pa.CLSCompliant) {
343
Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
345
Report.Warning (3012, 1, a.Location,
346
"You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
347
} else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) {
348
Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ());
349
Report.Warning (3017, 1, a.Location,
350
"You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
355
builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
358
public override void CloseContainer ()
360
if (anonymous_types != null) {
361
foreach (var atypes in anonymous_types)
362
foreach (var at in atypes.Value)
363
at.CloseContainer ();
366
base.CloseContainer ();
369
public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
371
return builder.DefineType (name, attr, null, typeSize);
375
// Creates alias global namespace
377
public RootNamespace CreateRootNamespace (string alias)
379
if (alias == global_ns.Alias) {
380
RootNamespace.Error_GlobalNamespaceRedefined (Report, Location.Null);
385
if (!alias_ns.TryGetValue (alias, out rn)) {
386
rn = new RootNamespace (alias);
387
alias_ns.Add (alias, rn);
393
public void Create (AssemblyDefinition assembly, ModuleBuilder moduleBuilder)
395
this.assembly = assembly;
396
builder = moduleBuilder;
399
public override bool Define ()
403
ExpandBaseInterfaces ();
407
HasTypesFullyDefined = true;
412
public override bool DefineContainer ()
416
return base.DefineContainer ();
419
public void EnableRedefinition ()
424
public override void EmitContainer ()
426
if (OptAttributes != null)
427
OptAttributes.Emit ();
429
if (Compiler.Settings.Unsafe && !assembly.IsSatelliteAssembly) {
430
var pa = PredefinedAttributes.UnverifiableCode;
432
pa.EmitAttribute (builder);
435
foreach (var tc in containers) {
439
base.EmitContainer ();
441
if (Compiler.Report.Errors == 0 && !Compiler.Settings.WriteMetadataOnly)
444
if (anonymous_types != null) {
445
foreach (var atypes in anonymous_types)
446
foreach (var at in atypes.Value)
451
internal override void GenerateDocComment (DocumentationBuilder builder)
453
foreach (var tc in containers)
454
tc.GenerateDocComment (builder);
457
public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
459
List<AnonymousTypeClass> candidates;
460
if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
464
foreach (AnonymousTypeClass at in candidates) {
465
for (i = 0; i < parameters.Count; ++i) {
466
if (!parameters [i].Equals (at.Parameters [i]))
470
if (i == parameters.Count)
478
// Return container with awaiter definition. It never returns null
479
// but all container member can be null for easier error reporting
481
public AwaiterDefinition GetAwaiter (TypeSpec type)
483
AwaiterDefinition awaiter;
484
if (awaiters.TryGetValue (type, out awaiter))
487
awaiter = new AwaiterDefinition ();
490
// Predefined: bool IsCompleted { get; }
492
awaiter.IsCompleted = MemberCache.FindMember (type, MemberFilter.Property ("IsCompleted", Compiler.BuiltinTypes.Bool),
493
BindingRestriction.InstanceOnly) as PropertySpec;
496
// Predefined: GetResult ()
498
// The method return type is also result type of await expression
500
awaiter.GetResult = MemberCache.FindMember (type, MemberFilter.Method ("GetResult", 0,
501
ParametersCompiled.EmptyReadOnlyParameters, null),
502
BindingRestriction.InstanceOnly) as MethodSpec;
505
// Predefined: INotifyCompletion.OnCompleted (System.Action)
507
var nc = PredefinedTypes.INotifyCompletion;
508
awaiter.INotifyCompletion = !nc.Define () || type.ImplementsInterface (nc.TypeSpec, false);
510
awaiters.Add (type, awaiter);
514
public override void GetCompletionStartingWith (string prefix, List<string> results)
516
var names = Evaluator.GetVarNames ();
517
results.AddRange (names.Where (l => l.StartsWith (prefix)));
520
public RootNamespace GetRootNamespace (string name)
523
alias_ns.TryGetValue (name, out rn);
527
public override string GetSignatureForError ()
532
public void InitializePredefinedTypes ()
534
predefined_attributes = new PredefinedAttributes (this);
535
predefined_types = new PredefinedTypes (this);
536
predefined_members = new PredefinedMembers (this);
539
public override bool IsClsComplianceRequired ()
541
return DeclaringAssembly.IsCLSCompliant;
544
public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
546
Attribute a = OptAttributes.Search ("assembly", a_type);
553
public void SetDeclaringAssembly (AssemblyDefinition assembly)
555
// TODO: This setter is quite ugly but I have not found a way around it yet
556
this.assembly = assembly;