Browse Source

Make virtualizer correctly generate modreqs for in and out parameters on newly virtual methods

pull/62/head
Anairkoen Schno 3 years ago
parent
commit
24643eb9b0
Signed by: DaNike GPG Key ID: BEFB74D5F3FC4387
1 changed files with 64 additions and 1 deletions
  1. +64
    -1
      IPA.Injector/Virtualizer.cs

+ 64
- 1
IPA.Injector/Virtualizer.cs View File

@ -1,5 +1,7 @@
using Mono.Cecil; using Mono.Cecil;
using System;
using Mono.Cecil.Rocks;
using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
@ -67,6 +69,9 @@ namespace IPA.Injector
} }
} }
private TypeReference inModreqRef;
private TypeReference outModreqRef;
private void VirtualizeType(TypeDefinition type) private void VirtualizeType(TypeDefinition type)
{ {
if(type.IsSealed) if(type.IsSealed)
@ -100,6 +105,21 @@ namespace IPA.Injector
&& !method.IsGenericInstance && !method.IsGenericInstance
&& !method.HasOverrides) && !method.HasOverrides)
{ {
// fix In and Out parameters to have the modreqs required by the compiler
foreach (var param in method.Parameters)
{
if (param.IsIn)
{
inModreqRef ??= module.ImportReference(typeof(System.Runtime.InteropServices.InAttribute));
param.ParameterType = AddModreqIfNotExist(param.ParameterType, inModreqRef);
}
if (param.IsOut)
{
outModreqRef ??= module.ImportReference(typeof(System.Runtime.InteropServices.OutAttribute));
param.ParameterType = AddModreqIfNotExist(param.ParameterType, outModreqRef);
}
}
method.IsVirtual = true; method.IsVirtual = true;
method.IsPublic = true; method.IsPublic = true;
method.IsPrivate = false; method.IsPrivate = false;
@ -114,6 +134,49 @@ namespace IPA.Injector
} }
} }
private TypeReference AddModreqIfNotExist(TypeReference type, TypeReference mod)
{
var (element, opt, req) = GetDecomposedModifiers(type);
if (!req.Contains(mod))
{
req.Add(mod);
}
return BuildModifiedType(element, opt, req);
}
private (TypeReference Element, List<TypeReference> ModOpt, List<TypeReference> ModReq) GetDecomposedModifiers(TypeReference type)
{
var opt = new List<TypeReference>();
var req = new List<TypeReference>();
while (type is IModifierType modif)
{
if (type.IsOptionalModifier)
opt.Add(modif.ModifierType);
if (type.IsRequiredModifier)
req.Add(modif.ModifierType);
type = modif.ElementType;
}
return (type, opt, req);
}
private TypeReference BuildModifiedType(TypeReference type, IEnumerable<TypeReference> opt, IEnumerable<TypeReference> req)
{
foreach (var mod in req)
{
type = type.MakeRequiredModifierType(mod);
}
foreach (var mod in opt)
{
type = type.MakeOptionalModifierType(mod);
}
return type;
}
#region IDisposable Support #region IDisposable Support
private bool disposedValue = false; // To detect redundant calls private bool disposedValue = false; // To detect redundant calls


Loading…
Cancel
Save