/// <summary> /// Applies the patch described in the given PatchingManifest to the TargetAssembly. /// </summary> /// <param name="manifest">The PatchingManifest. Note that the instance will be populated with additional information (such as newly created types) during execution.</param> /// <param name="o"></param> public void PatchManifest(PatchingManifest manifest, IProgressMonitor o) { /* The point of this method is to introduce all the patched elements in the correct order. * * Standard order of business for order between modify/remove/update: * 1. Remove Xs * 2. Create new Xs * 3. Update existing Xs (+ those we just created) */ manifest.Specialize(TargetAssembly); o.TaskTitle = $"{manifest.PatchAssembly.Name.Name}"; o.Current = 0; o.Total = 11; AssemblyDefinition targetAssemblyBackup = null; if (UseBackup) { targetAssemblyBackup = TargetAssembly.Clone(); } try { CurrentMemberCache = manifest.CreateCache(); //+INTRODUCE NEW TYPES //Declare all the new types, in the order of their nesting level (.e.g topmost types, nested types, types nested in those, etc), //But don't set anything that references other things, like BaseType, interfaces, custom attributes, etc. //Type parameters *are* added at this stage, but no constraints are specified. //DEPENDENCIES: None o.TaskText = "Introducing Types"; IntroduceTypes(manifest.TypeActions); o.Current++; //+REMOVE EXISTING METHODS //Remove any methods that need removing. //DEPENDENCIES: Probably none o.TaskText = "Removing Methods"; RemoveMethods(manifest.MethodActions); o.Current++; //+INTRODUCE NEW METHOD AND METHOD TYPE DEFINITIONS //Declare all the new methods and their type parameters, but do not set nything that references other types, //including return type, parameter types, and type parameter constraints //This is because method type variables must already exist. //This is performed now because types can reference attribute constructors that don't exist until we create them, //Don't set custom attributes in this stage. //DEPENDENCIES: Type definitions (when introduced to new types) o.TaskText = "Introducing Methods"; IntroduceMethods(manifest.MethodActions); o.Current++; //+UPDATE METHOD DECLERATIONS //Update method declerations with parameters and return types //We do this separately, because a method's parameters and return types depend on that method's generic parameters //Don't set custom attributes in this stage though it's possible to do so. //This is to avoid code duplication. //DEPENDENCIES: Type definitions, method definitions o.TaskText = "Updating Type Declerations"; UpdateMethodDeclerations(manifest.MethodActions); o.Current++; //+IMPORT ASSEMBLY/MODULE CUSTOM ATTRIBUTES //Add any custom attributes for things that aren't part of the method/type hierarchy, such as assemblies. //DEPENDENCIES: Method definitions, type definitions. (for attribute types and attribute constructors) o.TaskText = "Importing Assembly/Module Attributes"; var patchingAssembly = manifest.PatchAssembly; //for assmebly: CopyCustomAttributesByImportAttribute(TargetAssembly, patchingAssembly, patchingAssembly.GetCustomAttribute <ImportCustomAttributesAttribute>()); //for module: CopyCustomAttributesByImportAttribute(TargetAssembly.MainModule, patchingAssembly.MainModule, patchingAssembly.MainModule.GetCustomAttribute <ImportCustomAttributesAttribute>()); o.Current++; //+UPDATE TYPE DEFINITIONS //Set the type information we didn't set in (1), according to the same order, including custom attributes. //When/if modifying type inheritance is allowed, this process will occur at this stage. //DEPENDENCIES: Type definitions (obviously), method definitions (for attribute constructors) o.TaskText = "Updating Type Definitions"; UpdateTypes(manifest.TypeActions); o.Current++; //+FIELDS //remove/define/modify fields. This is where most enum processing happens. Custom attributes are set at this stage. //DEPENDENCIES: Type definitions, method definitions (for attribute constructors) o.TaskText = "Processing Fields"; ClearReplacedTypes(manifest.TypeActions); RemoveFields(manifest.FieldActions); IntroduceFields(manifest.FieldActions); UpdateFields(manifest.FieldActions); o.Current++; //+PROPERTIES //Remove/define/modify properties. This doesn't change anything about methods. Custom attributes are set at this stage. //DEPENDENCIES: Type definitions, method definitions (attribute constructors, getter/setters) o.TaskText = "Processing Properties"; RemoveProperties(manifest.PropertyActions); IntroduceProperties(manifest.PropertyActions); UpdateProperties(manifest.PropertyActions); o.Current++; //+EVENTS //Remove/define/modify events. This doesn't change anything about methods. Custom attributes are set at this stage. //DEPENENCIES: Type definitions, method definitions (attribute constructors, add/remove/invoke handlers) o.TaskText = "Introducing Events"; RemoveEvents(manifest.EventActions); IntroduceEvents(manifest.EventActions); UpdateEvents(manifest.EventActions); o.Current++; //+FINALIZE METHODS, GENERATE METHOD BODIES //Fill/modify the bodies of all remaining methods, and also modify accessibility/attributes of existing ones. //Note that methods that are the source of DuplicatesBody will be resolved in their unmodified version, //so the modifications won't influence this functionality. //Custom attributes are set at this stage. //Also, explicit overrides (what in C# is explicit interface implementation) are specified here. //DEPENDENCIES: Type definitions, method definitions, method signature elements, field definitions o.TaskText = "Updating Method Bodies"; UpdateMethods(manifest.MethodActions); o.Current++; //+ADD PATCHING HISTORY TO ASSEMBLY o.TaskText = "Updating History"; if (EmbedHistory) { TargetAssembly.AddPatchedByAssemblyAttribute(manifest.PatchAssembly, _assemblyHistoryIndex++, OriginalAssemblyMetadata); } o.Current++; } catch { if (UseBackup) { TargetAssembly = targetAssemblyBackup; } throw; } }