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.Reflection;
16 using System.Reflection.Emit;
17 using System.Runtime.InteropServices;
18 using Mono.CompilerServices.SymbolWriter;
23 // Module (top-level type) container
25 public class ModuleContainer : TypeContainer
27 public CharSet DefaultCharSet = CharSet.Ansi;
28 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
30 Dictionary<int, List<AnonymousTypeClass>> anonymous_types;
32 AssemblyDefinition assembly;
33 readonly CompilerContext context;
34 readonly RootNamespace global_ns;
35 Dictionary<string, RootNamespace> alias_ns;
37 ModuleBuilder builder;
38 int static_data_counter;
41 public List<Enum> hack_corlib_enums = new List<Enum> ();
43 bool has_default_charset;
44 bool has_extenstion_method;
46 PredefinedAttributes predefined_attributes;
47 PredefinedTypes predefined_types;
49 static readonly string[] attribute_targets = new string[] { "assembly", "module" };
51 public ModuleContainer (CompilerContext context)
52 : base (null, null, MemberName.Null, null, 0)
54 this.context = context;
56 caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected);
58 types = new List<TypeContainer> ();
59 anonymous_types = new Dictionary<int, List<AnonymousTypeClass>> ();
60 global_ns = new GlobalRootNamespace ();
61 alias_ns = new Dictionary<string, RootNamespace> ();
66 public override AttributeTargets AttributeTargets {
68 return AttributeTargets.Assembly;
72 public ModuleBuilder Builder {
78 public override CompilerContext Compiler {
84 public override AssemblyDefinition DeclaringAssembly {
90 public bool HasDefaultCharSet {
92 return has_default_charset;
96 public bool HasExtensionMethod {
98 return has_extenstion_method;
101 has_extenstion_method = value;
106 // Returns module global:: namespace
108 public RootNamespace GlobalRootNamespace {
114 public override ModuleContainer Module {
120 internal PredefinedAttributes PredefinedAttributes {
122 return predefined_attributes;
126 internal PredefinedTypes PredefinedTypes {
128 return predefined_types;
132 public override string[] ValidAttributeTargets {
134 return attribute_targets;
140 public void AddAnonymousType (AnonymousTypeClass type)
142 List<AnonymousTypeClass> existing;
143 if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing))
144 if (existing == null) {
145 existing = new List<AnonymousTypeClass> ();
146 anonymous_types.Add (type.Parameters.Count, existing);
152 public void AddAttributes (List<Attribute> attrs)
154 AddAttributes (attrs, this);
157 public void AddAttributes (List<Attribute> attrs, IMemberContext context)
159 foreach (Attribute a in attrs)
160 a.AttachTo (this, context);
162 if (attributes == null) {
163 attributes = new Attributes (attrs);
166 attributes.AddAttributes (attrs);
169 public override TypeContainer AddPartial (TypeContainer nextPart)
171 return AddPartial (nextPart, nextPart.Name);
174 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
176 if (a.Target == AttributeTargets.Assembly) {
177 assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
181 if (a.Type == pa.CLSCompliant) {
182 Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
184 Report.Warning (3012, 1, a.Location,
185 "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
186 } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) {
187 Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ());
188 Report.Warning (3017, 1, a.Location,
189 "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
194 builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
197 public new void CloseType ()
201 foreach (TypeContainer tc in types) {
205 if (compiler_generated != null)
206 foreach (CompilerGeneratedClass c in compiler_generated)
210 // If we have a <PrivateImplementationDetails> class, close it
212 if (TypeBuilder != null) {
213 var cg = PredefinedAttributes.CompilerGenerated;
214 cg.EmitAttribute (TypeBuilder);
215 TypeBuilder.CreateType ();
219 public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
221 return builder.DefineType (name, attr, null, typeSize);
225 // Creates alias global namespace
227 public RootNamespace CreateRootNamespace (string alias)
229 if (alias == global_ns.Alias) {
230 NamespaceEntry.Error_GlobalNamespaceRedefined (Location.Null, Report);
235 if (!alias_ns.TryGetValue (alias, out rn)) {
236 rn = new RootNamespace (alias);
237 alias_ns.Add (alias, rn);
243 public new void Define ()
245 builder = assembly.CreateModuleBuilder ();
247 // FIXME: Temporary hack for repl to reset
250 // TODO: It should be done much later when the types are resolved
251 // but that require DefineType clean-up
252 ResolveGlobalAttributes ();
254 foreach (TypeContainer tc in types)
257 InitializePredefinedTypes ();
259 foreach (TypeContainer tc in types)
262 foreach (TypeContainer tc in types)
263 tc.ResolveTypeParameters ();
265 foreach (TypeContainer tc in types) {
268 } catch (Exception e) {
269 throw new InternalErrorException (tc, e);
274 public override void Emit ()
276 if (OptAttributes != null)
277 OptAttributes.Emit ();
279 if (RootContext.Unsafe) {
280 var pa = PredefinedAttributes.UnverifiableCode;
282 pa.EmitAttribute (builder);
285 foreach (var tc in types)
286 tc.DefineConstants ();
290 foreach (TypeContainer tc in types)
293 if (Compiler.Report.Errors > 0)
296 foreach (TypeContainer tc in types)
299 if (compiler_generated != null)
300 foreach (var c in compiler_generated)
304 public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
306 List<AnonymousTypeClass> candidates;
307 if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
311 foreach (AnonymousTypeClass at in candidates) {
312 for (i = 0; i < parameters.Count; ++i) {
313 if (!parameters [i].Equals (at.Parameters [i]))
317 if (i == parameters.Count)
324 public RootNamespace GetRootNamespace (string name)
327 alias_ns.TryGetValue (name, out rn);
331 public override string GetSignatureForError ()
338 if (RootContext.StdLib)
342 // HACK: When building corlib mcs uses loaded mscorlib which
343 // has different predefined types and this method sets mscorlib types
344 // to be same to avoid type check errors in CreateType.
346 var type = typeof (Type);
347 var system_4_type_arg = new[] { type, type, type, type };
349 MethodInfo set_corlib_type_builders =
350 typeof (System.Reflection.Emit.AssemblyBuilder).GetMethod (
351 "SetCorlibTypeBuilders", BindingFlags.NonPublic | BindingFlags.Instance, null,
352 system_4_type_arg, null);
354 if (set_corlib_type_builders == null) {
355 Compiler.Report.Warning (-26, 3,
356 "The compilation may fail due to missing `System.Reflection.Emit.AssemblyBuilder.SetCorlibTypeBuilders(...)' method");
360 object[] args = new object[4];
361 args[0] = TypeManager.object_type.GetMetaInfo ();
362 args[1] = TypeManager.value_type.GetMetaInfo ();
363 args[2] = TypeManager.enum_type.GetMetaInfo ();
364 args[3] = TypeManager.void_type.GetMetaInfo ();
365 set_corlib_type_builders.Invoke (assembly.Builder, args);
368 void HackCorlibEnums ()
370 if (RootContext.StdLib)
373 // Another Mono corlib HACK
374 // mono_class_layout_fields requires to have enums created
375 // before creating a class which used the enum for any of its fields
376 foreach (var e in hack_corlib_enums)
380 public void InitializePredefinedTypes ()
382 predefined_attributes = new PredefinedAttributes (this);
383 predefined_types = new PredefinedTypes (this);
386 public override bool IsClsComplianceRequired ()
388 return DeclaringAssembly.IsCLSCompliant;
391 public AssemblyDefinition MakeExecutable (string name)
393 assembly = new AssemblyDefinition (this, name);
397 public AssemblyDefinition MakeExecutable (string name, string fileName)
399 assembly = new AssemblyDefinition (this, name, fileName);
404 // Makes an initialized struct, returns the field builder that
405 // references the data. Thanks go to Sergey Chaban for researching
406 // how to do this. And coming up with a shorter mechanism than I
407 // was able to figure out.
409 // This works but makes an implicit public struct $ArrayType$SIZE and
410 // makes the fields point to it. We could get more control if we did
413 // 1. DefineNestedType on the impl_details_class with our struct.
415 // 2. Define the field on the impl_details_class
417 public FieldBuilder MakeStaticData (byte[] data)
419 if (TypeBuilder == null) {
420 TypeBuilder = builder.DefineType ("<PrivateImplementationDetails>",
421 TypeAttributes.NotPublic, TypeManager.object_type.GetMetaInfo ());
424 var fb = TypeBuilder.DefineInitializedData (
425 "$$field-" + (static_data_counter++), data,
426 FieldAttributes.Static | FieldAttributes.Assembly);
431 protected override bool AddMemberType (TypeContainer ds)
433 if (!AddToContainer (ds, ds.Name))
435 ds.NamespaceEntry.NS.AddType (ds.Definition);
439 protected override void RemoveMemberType (DeclSpace ds)
441 ds.NamespaceEntry.NS.RemoveDeclSpace (ds.Basename);
442 base.RemoveMemberType (ds);
446 /// It is called very early therefore can resolve only predefined attributes
448 void ResolveGlobalAttributes ()
450 if (OptAttributes == null)
453 if (!OptAttributes.CheckTargets ())
456 // FIXME: Define is wrong as the type may not exist yet
457 var DefaultCharSet_attr = new PredefinedAttribute (this, "System.Runtime.InteropServices", "DefaultCharSetAttribute");
458 DefaultCharSet_attr.Define ();
459 Attribute a = ResolveModuleAttribute (DefaultCharSet_attr);
461 has_default_charset = true;
462 DefaultCharSet = a.GetCharSetValue ();
463 switch (DefaultCharSet) {
468 DefaultCharSetType = TypeAttributes.AutoClass;
470 case CharSet.Unicode:
471 DefaultCharSetType = TypeAttributes.UnicodeClass;
474 Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid",
475 DefaultCharSet_attr.GetSignatureForError ());
481 public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
483 Attribute a = OptAttributes.Search ("assembly", a_type);
490 Attribute ResolveModuleAttribute (PredefinedAttribute a_type)
492 Attribute a = OptAttributes.Search ("module", a_type);
500 class RootDeclSpace : TypeContainer {
501 public RootDeclSpace (NamespaceEntry ns)
502 : base (ns, null, MemberName.Null, null, 0)
504 PartialContainer = RootContext.ToplevelTypes;
507 public override AttributeTargets AttributeTargets {
508 get { throw new InternalErrorException ("should not be called"); }
511 public override CompilerContext Compiler {
513 return PartialContainer.Compiler;
517 public override string DocCommentHeader {
518 get { throw new InternalErrorException ("should not be called"); }
521 public override void DefineType ()
523 throw new InternalErrorException ("should not be called");
526 public override ModuleContainer Module {
528 return PartialContainer.Module;
532 public override bool IsClsComplianceRequired ()
534 return PartialContainer.IsClsComplianceRequired ();
537 public override FullNamedExpression LookupNamespaceAlias (string name)
539 return NamespaceEntry.LookupNamespaceAlias (name);