mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
512 lines
12 KiB
512 lines
12 KiB
// |
|
// module.cs: keeps a tree representation of the generated code |
|
// |
|
// Authors: Miguel de Icaza (miguel@gnu.org) |
|
// Marek Safar (marek.safar@gmail.com) |
|
// |
|
// Dual licensed under the terms of the MIT X11 or GNU GPL |
|
// |
|
// Copyright 2001-2003 Ximian, Inc (http://www.ximian.com) |
|
// Copyright 2003-2008 Novell, Inc. |
|
// Copyright 2011 Xamarin Inc |
|
// |
|
|
|
using System; |
|
using System.Collections.Generic; |
|
using System.Runtime.InteropServices; |
|
using Mono.CompilerServices.SymbolWriter; |
|
using System.Linq; |
|
|
|
#if STATIC |
|
using IKVM.Reflection; |
|
using IKVM.Reflection.Emit; |
|
#else |
|
using System.Reflection; |
|
using System.Reflection.Emit; |
|
#endif |
|
|
|
namespace Mono.CSharp |
|
{ |
|
// |
|
// Module (top-level type) container |
|
// |
|
public sealed class ModuleContainer : TypeContainer |
|
{ |
|
#if STATIC |
|
// |
|
// Compiler generated container for static data |
|
// |
|
sealed class StaticDataContainer : CompilerGeneratedClass |
|
{ |
|
readonly Dictionary<int, Struct> size_types; |
|
int fields; |
|
|
|
public StaticDataContainer (ModuleContainer module) |
|
: base (module, new MemberName ("<PrivateImplementationDetails>" + module.builder.ModuleVersionId.ToString ("B"), Location.Null), Modifiers.STATIC) |
|
{ |
|
size_types = new Dictionary<int, Struct> (); |
|
} |
|
|
|
public override void CloseContainer () |
|
{ |
|
base.CloseContainer (); |
|
|
|
foreach (var entry in size_types) { |
|
entry.Value.CloseContainer (); |
|
} |
|
} |
|
|
|
public FieldSpec DefineInitializedData (byte[] data, Location loc) |
|
{ |
|
Struct size_type; |
|
if (!size_types.TryGetValue (data.Length, out size_type)) { |
|
// |
|
// Build common type for this data length. We cannot use |
|
// DefineInitializedData because it creates public type, |
|
// and its name is not unique among modules |
|
// |
|
size_type = new Struct (this, new MemberName ("$ArrayType=" + data.Length, loc), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, null); |
|
size_type.CreateContainer (); |
|
size_type.DefineContainer (); |
|
|
|
size_types.Add (data.Length, size_type); |
|
|
|
// It has to work even if StructLayoutAttribute does not exist |
|
size_type.TypeBuilder.__SetLayout (1, data.Length); |
|
} |
|
|
|
var name = "$field-" + fields.ToString ("X"); |
|
++fields; |
|
const Modifiers fmod = Modifiers.STATIC | Modifiers.INTERNAL; |
|
var fbuilder = TypeBuilder.DefineField (name, size_type.CurrentType.GetMetaInfo (), ModifiersExtensions.FieldAttr (fmod) | FieldAttributes.HasFieldRVA); |
|
fbuilder.__SetDataAndRVA (data); |
|
|
|
return new FieldSpec (CurrentType, null, size_type.CurrentType, fbuilder, fmod); |
|
} |
|
} |
|
|
|
StaticDataContainer static_data; |
|
|
|
// |
|
// Makes const data field inside internal type container |
|
// |
|
public FieldSpec MakeStaticData (byte[] data, Location loc) |
|
{ |
|
if (static_data == null) { |
|
static_data = new StaticDataContainer (this); |
|
static_data.CreateContainer (); |
|
static_data.DefineContainer (); |
|
|
|
AddCompilerGeneratedClass (static_data); |
|
} |
|
|
|
return static_data.DefineInitializedData (data, loc); |
|
} |
|
#endif |
|
|
|
public CharSet? DefaultCharSet; |
|
public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass; |
|
|
|
readonly Dictionary<int, List<AnonymousTypeClass>> anonymous_types; |
|
readonly Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> array_types; |
|
readonly Dictionary<TypeSpec, PointerContainer> pointer_types; |
|
readonly Dictionary<TypeSpec, ReferenceContainer> reference_types; |
|
readonly Dictionary<TypeSpec, MethodSpec> attrs_cache; |
|
|
|
AssemblyDefinition assembly; |
|
readonly CompilerContext context; |
|
readonly RootNamespace global_ns; |
|
readonly Dictionary<string, RootNamespace> alias_ns; |
|
|
|
ModuleBuilder builder; |
|
|
|
bool has_extenstion_method; |
|
|
|
PredefinedAttributes predefined_attributes; |
|
PredefinedTypes predefined_types; |
|
PredefinedMembers predefined_members; |
|
|
|
static readonly string[] attribute_targets = new string[] { "assembly", "module" }; |
|
|
|
public ModuleContainer (CompilerContext context) |
|
: base (null, MemberName.Null, null, 0) |
|
{ |
|
this.context = context; |
|
|
|
caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected); |
|
|
|
containers = new List<TypeContainer> (); |
|
anonymous_types = new Dictionary<int, List<AnonymousTypeClass>> (); |
|
global_ns = new GlobalRootNamespace (); |
|
alias_ns = new Dictionary<string, RootNamespace> (); |
|
array_types = new Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> (); |
|
pointer_types = new Dictionary<TypeSpec, PointerContainer> (); |
|
reference_types = new Dictionary<TypeSpec, ReferenceContainer> (); |
|
attrs_cache = new Dictionary<TypeSpec, MethodSpec> (); |
|
} |
|
|
|
#region Properties |
|
|
|
internal Dictionary<ArrayContainer.TypeRankPair, ArrayContainer> ArrayTypesCache { |
|
get { |
|
return array_types; |
|
} |
|
} |
|
|
|
// |
|
// Cache for parameter-less attributes |
|
// |
|
internal Dictionary<TypeSpec, MethodSpec> AttributeConstructorCache { |
|
get { |
|
return attrs_cache; |
|
} |
|
} |
|
|
|
public override AttributeTargets AttributeTargets { |
|
get { |
|
return AttributeTargets.Assembly; |
|
} |
|
} |
|
|
|
public ModuleBuilder Builder { |
|
get { |
|
return builder; |
|
} |
|
} |
|
|
|
public override CompilerContext Compiler { |
|
get { |
|
return context; |
|
} |
|
} |
|
|
|
public int CounterAnonymousTypes { get; set; } |
|
public int CounterAnonymousMethods { get; set; } |
|
public int CounterAnonymousContainers { get; set; } |
|
public int CounterSwitchTypes { get; set; } |
|
|
|
public AssemblyDefinition DeclaringAssembly { |
|
get { |
|
return assembly; |
|
} |
|
} |
|
|
|
internal DocumentationBuilder DocumentationBuilder { |
|
get; set; |
|
} |
|
|
|
public override string DocCommentHeader { |
|
get { |
|
throw new NotSupportedException (); |
|
} |
|
} |
|
|
|
public Evaluator Evaluator { |
|
get; set; |
|
} |
|
|
|
public bool HasDefaultCharSet { |
|
get { |
|
return DefaultCharSet.HasValue; |
|
} |
|
} |
|
|
|
public bool HasExtensionMethod { |
|
get { |
|
return has_extenstion_method; |
|
} |
|
set { |
|
has_extenstion_method = value; |
|
} |
|
} |
|
|
|
public bool HasTypesFullyDefined { |
|
get; set; |
|
} |
|
|
|
// |
|
// Returns module global:: namespace |
|
// |
|
public RootNamespace GlobalRootNamespace { |
|
get { |
|
return global_ns; |
|
} |
|
} |
|
|
|
public override ModuleContainer Module { |
|
get { |
|
return this; |
|
} |
|
} |
|
|
|
internal Dictionary<TypeSpec, PointerContainer> PointerTypesCache { |
|
get { |
|
return pointer_types; |
|
} |
|
} |
|
|
|
internal PredefinedAttributes PredefinedAttributes { |
|
get { |
|
return predefined_attributes; |
|
} |
|
} |
|
|
|
internal PredefinedMembers PredefinedMembers { |
|
get { |
|
return predefined_members; |
|
} |
|
} |
|
|
|
internal PredefinedTypes PredefinedTypes { |
|
get { |
|
return predefined_types; |
|
} |
|
} |
|
|
|
internal Dictionary<TypeSpec, ReferenceContainer> ReferenceTypesCache { |
|
get { |
|
return reference_types; |
|
} |
|
} |
|
|
|
public override string[] ValidAttributeTargets { |
|
get { |
|
return attribute_targets; |
|
} |
|
} |
|
|
|
#endregion |
|
|
|
public override void Accept (StructuralVisitor visitor) |
|
{ |
|
visitor.Visit (this); |
|
} |
|
|
|
public void AddAnonymousType (AnonymousTypeClass type) |
|
{ |
|
List<AnonymousTypeClass> existing; |
|
if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing)) |
|
if (existing == null) { |
|
existing = new List<AnonymousTypeClass> (); |
|
anonymous_types.Add (type.Parameters.Count, existing); |
|
} |
|
|
|
existing.Add (type); |
|
} |
|
|
|
public void AddAttribute (Attribute attr, IMemberContext context) |
|
{ |
|
attr.AttachTo (this, context); |
|
|
|
if (attributes == null) { |
|
attributes = new Attributes (attr); |
|
return; |
|
} |
|
|
|
attributes.AddAttribute (attr); |
|
} |
|
|
|
public override void AddTypeContainer (TypeContainer tc) |
|
{ |
|
containers.Add (tc); |
|
} |
|
|
|
public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa) |
|
{ |
|
if (a.Target == AttributeTargets.Assembly) { |
|
assembly.ApplyAttributeBuilder (a, ctor, cdata, pa); |
|
return; |
|
} |
|
|
|
if (a.Type == pa.DefaultCharset) { |
|
switch (a.GetCharSetValue ()) { |
|
case CharSet.Ansi: |
|
case CharSet.None: |
|
break; |
|
case CharSet.Auto: |
|
DefaultCharSet = CharSet.Auto; |
|
DefaultCharSetType = TypeAttributes.AutoClass; |
|
break; |
|
case CharSet.Unicode: |
|
DefaultCharSet = CharSet.Unicode; |
|
DefaultCharSetType = TypeAttributes.UnicodeClass; |
|
break; |
|
default: |
|
Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid", |
|
a.GetSignatureForError ()); |
|
break; |
|
} |
|
} else if (a.Type == pa.CLSCompliant) { |
|
Attribute cls = DeclaringAssembly.CLSCompliantAttribute; |
|
if (cls == null) { |
|
Report.Warning (3012, 1, a.Location, |
|
"You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking"); |
|
} else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) { |
|
Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ()); |
|
Report.Warning (3017, 1, a.Location, |
|
"You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly"); |
|
return; |
|
} |
|
} |
|
|
|
builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata); |
|
} |
|
|
|
public override void CloseContainer () |
|
{ |
|
if (anonymous_types != null) { |
|
foreach (var atypes in anonymous_types) |
|
foreach (var at in atypes.Value) |
|
at.CloseContainer (); |
|
} |
|
|
|
base.CloseContainer (); |
|
} |
|
|
|
public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize) |
|
{ |
|
return builder.DefineType (name, attr, null, typeSize); |
|
} |
|
|
|
// |
|
// Creates alias global namespace |
|
// |
|
public RootNamespace CreateRootNamespace (string alias) |
|
{ |
|
if (alias == global_ns.Alias) { |
|
RootNamespace.Error_GlobalNamespaceRedefined (Report, Location.Null); |
|
return global_ns; |
|
} |
|
|
|
RootNamespace rn; |
|
if (!alias_ns.TryGetValue (alias, out rn)) { |
|
rn = new RootNamespace (alias); |
|
alias_ns.Add (alias, rn); |
|
} |
|
|
|
return rn; |
|
} |
|
|
|
public void Create (AssemblyDefinition assembly, ModuleBuilder moduleBuilder) |
|
{ |
|
this.assembly = assembly; |
|
builder = moduleBuilder; |
|
} |
|
|
|
public override bool Define () |
|
{ |
|
DefineContainer (); |
|
|
|
base.Define (); |
|
|
|
HasTypesFullyDefined = true; |
|
|
|
return true; |
|
} |
|
|
|
public override bool DefineContainer () |
|
{ |
|
DefineNamespace (); |
|
|
|
return base.DefineContainer (); |
|
} |
|
|
|
public override void EmitContainer () |
|
{ |
|
if (OptAttributes != null) |
|
OptAttributes.Emit (); |
|
|
|
if (Compiler.Settings.Unsafe) { |
|
var pa = PredefinedAttributes.UnverifiableCode; |
|
if (pa.IsDefined) |
|
pa.EmitAttribute (builder); |
|
} |
|
|
|
foreach (var tc in containers) { |
|
tc.PrepareEmit (); |
|
} |
|
|
|
base.EmitContainer (); |
|
|
|
if (Compiler.Report.Errors == 0) |
|
VerifyMembers (); |
|
|
|
if (anonymous_types != null) { |
|
foreach (var atypes in anonymous_types) |
|
foreach (var at in atypes.Value) |
|
at.EmitContainer (); |
|
} |
|
} |
|
|
|
internal override void GenerateDocComment (DocumentationBuilder builder) |
|
{ |
|
foreach (var tc in containers) |
|
tc.GenerateDocComment (builder); |
|
} |
|
|
|
public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters) |
|
{ |
|
List<AnonymousTypeClass> candidates; |
|
if (!anonymous_types.TryGetValue (parameters.Count, out candidates)) |
|
return null; |
|
|
|
int i; |
|
foreach (AnonymousTypeClass at in candidates) { |
|
for (i = 0; i < parameters.Count; ++i) { |
|
if (!parameters [i].Equals (at.Parameters [i])) |
|
break; |
|
} |
|
|
|
if (i == parameters.Count) |
|
return at; |
|
} |
|
|
|
return null; |
|
} |
|
|
|
public override void GetCompletionStartingWith (string prefix, List<string> results) |
|
{ |
|
var names = Evaluator.GetVarNames (); |
|
results.AddRange (names.Where (l => l.StartsWith (prefix))); |
|
} |
|
|
|
public RootNamespace GetRootNamespace (string name) |
|
{ |
|
RootNamespace rn; |
|
alias_ns.TryGetValue (name, out rn); |
|
return rn; |
|
} |
|
|
|
public override string GetSignatureForError () |
|
{ |
|
return "<module>"; |
|
} |
|
|
|
public void InitializePredefinedTypes () |
|
{ |
|
predefined_attributes = new PredefinedAttributes (this); |
|
predefined_types = new PredefinedTypes (this); |
|
predefined_members = new PredefinedMembers (this); |
|
} |
|
|
|
public override bool IsClsComplianceRequired () |
|
{ |
|
return DeclaringAssembly.IsCLSCompliant; |
|
} |
|
|
|
public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type) |
|
{ |
|
Attribute a = OptAttributes.Search ("assembly", a_type); |
|
if (a != null) { |
|
a.Resolve (); |
|
} |
|
return a; |
|
} |
|
|
|
public void SetDeclaringAssembly (AssemblyDefinition assembly) |
|
{ |
|
// TODO: This setter is quite ugly but I have not found a way around it yet |
|
this.assembly = assembly; |
|
} |
|
} |
|
}
|
|
|