.NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!
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

//
// 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;
}
}
}