/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using dnSpy.Debugger.DotNet.Metadata.Impl; namespace dnSpy.Debugger.DotNet.Metadata { /// /// A .NET assembly /// public abstract class DmdAssembly : DmdObject, IDmdCustomAttributeProvider, IDmdSecurityAttributeProvider { /// /// Dummy abstract method to make sure no-one outside this assembly can create their own /// private protected abstract void YouCantDeriveFromThisClass(); /// /// Gets the AppDomain /// public abstract DmdAppDomain AppDomain { get; } /// /// true if this is the corlib assembly /// public bool IsCorLib => this == AppDomain.CorLib; /// /// Creates a qualified type name /// /// Full assembly name of the type /// Full type name /// public static string CreateQualifiedName(string assemblyName, string typeName) => typeName + ", " + assemblyName; /// /// Gets the assembly name /// /// public abstract DmdReadOnlyAssemblyName GetName(); /// /// Gets the full name of the assembly /// public string FullName => GetName().ToString(); /// /// Gets the assembly location or an empty string /// public abstract string Location { get; } /// /// Gets the runtime version found in the metadata /// public abstract string ImageRuntimeVersion { get; } /// /// true if it's a dynamic assembly (types can be added at runtime) /// public bool IsDynamic => ManifestModule.IsDynamic; /// /// true if it's an in-memory assembly (eg. loaded from a array) /// public bool IsInMemory => ManifestModule.IsInMemory; /// /// true if it's a synthetic assembly; it's not loaded in the debugged process /// public bool IsSynthetic => ManifestModule.IsSynthetic; /// /// true if the assembly has been added to its AppDomain /// public abstract bool IsLoaded { get; } /// /// Gets the entry point or null /// public abstract DmdMethodInfo? EntryPoint { get; } /// /// Gets the first module of this assembly /// public abstract DmdModule ManifestModule { get; } /// /// Gets a type /// /// Type /// public DmdType? GetType(Type type) => GetType(type, DmdGetTypeOptions.None); /// /// Gets a type and throws if it couldn't be found /// /// /// public DmdType GetTypeThrow(Type type) => GetType(type, DmdGetTypeOptions.ThrowOnError)!; /// /// Gets a type /// /// Type /// Options /// public DmdType? GetType(Type type, DmdGetTypeOptions options) { if (type is null) throw new ArgumentNullException(nameof(type)); var fullname = type.FullName ?? throw new ArgumentException(); return GetType(fullname, options); } /// /// Gets a type in this assembly or null if it doesn't exist /// /// Name of type /// public DmdType? GetType(string name) => GetType(name, DmdGetTypeOptions.None); /// /// Gets a type and throws if it couldn't be found /// /// Name of type /// public DmdType GetTypeThrow(string name) => GetType(name, DmdGetTypeOptions.ThrowOnError)!; /// /// Gets a type in this assembly /// /// Name of type /// true to throw if the type doesn't exist /// public DmdType? GetType(string name, bool throwOnError) => GetType(name, throwOnError ? DmdGetTypeOptions.ThrowOnError : DmdGetTypeOptions.None); /// /// Gets a type in this assembly /// /// Name of type /// true to throw if the type doesn't exist /// true if case insensitive comparisons /// public DmdType? GetType(string name, bool throwOnError, bool ignoreCase) => GetType(name, (throwOnError ? DmdGetTypeOptions.ThrowOnError : 0) | (ignoreCase ? DmdGetTypeOptions.IgnoreCase : 0)); /// /// Gets a type /// /// Full name of the type () /// Options /// public abstract DmdType? GetType(string typeName, DmdGetTypeOptions options); /// /// Gets all public types in this assembly /// public IEnumerable ExportedTypes => GetExportedTypes(); /// /// Gets all public types in this assembly /// public abstract DmdType[] GetExportedTypes(); /// /// Gets all forwarded types (types that now exist in another assembly) /// /// public abstract DmdType[] GetForwardedTypes(); /// /// Gets all types in this assembly /// /// public DmdType[] GetTypes() { var modules = GetModules(); if (modules.Length == 1) return modules[0].GetTypes(); var list = new List(); foreach (var module in modules) list.AddRange(module.GetTypes()); return list.ToArray(); } /// /// Gets the security attributes /// public ReadOnlyCollection SecurityAttributes => GetSecurityAttributesData(); /// /// Gets the security attributes /// /// public abstract ReadOnlyCollection GetSecurityAttributesData(); /// /// Gets the custom attributes /// public ReadOnlyCollection CustomAttributes => GetCustomAttributesData(); /// /// Gets the custom attributes /// /// public abstract ReadOnlyCollection GetCustomAttributesData(); /// /// Checks if a custom attribute is present /// /// Full name of the custom attribute type /// true to check custom attributes in all base classes /// public bool IsDefined(string attributeTypeFullName, bool inherit) => CustomAttributesHelper.IsDefined(GetCustomAttributesData(), attributeTypeFullName); /// /// Checks if a custom attribute is present /// /// Custom attribute type /// true to check custom attributes in all base classes /// public bool IsDefined(DmdType? attributeType, bool inherit) => CustomAttributesHelper.IsDefined(GetCustomAttributesData(), attributeType); /// /// Checks if a custom attribute is present /// /// Custom attribute type /// true to check custom attributes in all base classes /// public bool IsDefined(Type attributeType, bool inherit) => CustomAttributesHelper.IsDefined(GetCustomAttributesData(), DmdTypeUtilities.ToDmdType(attributeType, AppDomain)); /// /// Finds a custom attribute /// /// Full name of the custom attribute type /// true to check custom attributes in all base classes /// public DmdCustomAttributeData? FindCustomAttribute(string attributeTypeFullName, bool inherit) => CustomAttributesHelper.Find(GetCustomAttributesData(), attributeTypeFullName); /// /// Finds a custom attribute /// /// Custom attribute type /// true to check custom attributes in all base classes /// public DmdCustomAttributeData? FindCustomAttribute(DmdType? attributeType, bool inherit) => CustomAttributesHelper.Find(GetCustomAttributesData(), attributeType); /// /// Finds a custom attribute /// /// Custom attribute type /// true to check custom attributes in all base classes /// public DmdCustomAttributeData? FindCustomAttribute(Type attributeType, bool inherit) => CustomAttributesHelper.Find(GetCustomAttributesData(), DmdTypeUtilities.ToDmdType(attributeType, AppDomain)); /// /// Creates an instance of a type /// /// Evaluation context /// Fully qualified name of type to create public object? CreateInstance(object? context, string typeName) => CreateInstance(context, typeName, false, DmdBindingFlags.Instance | DmdBindingFlags.Public, null, (IList?)null); /// /// Creates an instance of a type /// /// Evaluation context /// Fully qualified name of type to create /// true to ignore case public object? CreateInstance(object? context, string typeName, bool ignoreCase) => CreateInstance(context, typeName, ignoreCase, DmdBindingFlags.Instance | DmdBindingFlags.Public, null, (IList?)null); /// /// Creates an instance of a type /// /// Evaluation context /// Fully qualified name of type to create /// true to ignore case /// Binding attributes /// Constructor arguments or null public object? CreateInstance(object? context, string typeName, bool ignoreCase, DmdBindingFlags bindingAttr, object?[]? args) => CreateInstance(context, typeName, ignoreCase, bindingAttr, args, (IList?)null); /// /// Creates an instance of a type /// /// Evaluation context /// Fully qualified name of type to create /// true to ignore case /// Binding attributes /// Constructor arguments or null /// Constructor parameter types or null /// public object? CreateInstance(object? context, string typeName, bool ignoreCase, DmdBindingFlags bindingAttr, object?[]? args, IList? argTypes) { args ??= Array.Empty(); if (argTypes is not null && args.Length != argTypes.Count) throw new ArgumentException(); var type = GetType(typeName, false, ignoreCase); if (type is null) return null; DmdConstructorInfo? ctor; if (argTypes is not null) ctor = type.GetConstructor(bindingAttr, argTypes); else { ctor = null; foreach (var c in type.GetConstructors(bindingAttr)) { if (c.GetMethodSignature().GetParameterTypes().Count != args.Length) continue; if (ctor is not null) return null; ctor = c; } } return ctor?.Invoke(context, args); } /// /// Creates an instance of a type /// /// Evaluation context /// Fully qualified name of type to create /// true to ignore case /// Binding attributes /// Constructor arguments or null /// Constructor parameter types or null /// public object? CreateInstance(object? context, string typeName, bool ignoreCase, DmdBindingFlags bindingAttr, object?[]? args, IList? argTypes) => CreateInstance(context, typeName, ignoreCase, bindingAttr, args, argTypes.ToDmdType(AppDomain)); /// /// Gets all loaded modules /// public IEnumerable Modules => GetLoadedModules(); /// /// Gets all loaded modules /// /// public abstract DmdModule[] GetLoadedModules(); /// /// Gets all modules /// /// public abstract DmdModule[] GetModules(); /// /// Gets a module /// /// Name of module /// public abstract DmdModule? GetModule(string name); /// /// Gets all referenced assemblies /// /// public abstract DmdReadOnlyAssemblyName[] GetReferencedAssemblies(); /// /// Removes a module from the assembly /// /// Module to remove public abstract void Remove(DmdModule module); /// /// Gets the full name /// /// public sealed override string ToString() => FullName; } }