// dnlib: See LICENSE.txt for more info using System.Collections.Generic; namespace dnlib.DotNet { readonly struct GenericArgumentsStack { readonly List> argsStack; readonly bool isTypeVar; /// /// Constructor /// /// true if it's for generic types, false if generic methods public GenericArgumentsStack(bool isTypeVar) { argsStack = new List>(); this.isTypeVar = isTypeVar; } /// /// Pushes generic arguments /// /// The generic arguments public void Push(IList args) => argsStack.Add(args); /// /// Pops generic arguments /// /// The popped generic arguments public IList Pop() { int index = argsStack.Count - 1; var result = argsStack[index]; argsStack.RemoveAt(index); return result; } /// /// Resolves a generic argument /// /// Generic variable number /// A or null if none was found public TypeSig Resolve(uint number) { TypeSig result = null; for (int i = argsStack.Count - 1; i >= 0; i--) { var args = argsStack[i]; if (number >= args.Count) return null; var typeSig = args[(int)number]; var gvar = typeSig as GenericSig; if (gvar is null || gvar.IsTypeVar != isTypeVar) return typeSig; result = gvar; number = gvar.Number; } return result; } } /// /// Replaces generic type/method var with its generic argument /// sealed class GenericArguments { GenericArgumentsStack typeArgsStack = new GenericArgumentsStack(true); GenericArgumentsStack methodArgsStack = new GenericArgumentsStack(false); /// /// Pushes generic arguments /// /// The generic arguments public void PushTypeArgs(IList typeArgs) => typeArgsStack.Push(typeArgs); /// /// Pops generic arguments /// /// The popped generic arguments public IList PopTypeArgs() => typeArgsStack.Pop(); /// /// Pushes generic arguments /// /// The generic arguments public void PushMethodArgs(IList methodArgs) => methodArgsStack.Push(methodArgs); /// /// Pops generic arguments /// /// The popped generic arguments public IList PopMethodArgs() => methodArgsStack.Pop(); /// /// Replaces a generic type/method var with its generic argument (if any). If /// isn't a generic type/method var or if it can't /// be resolved, it itself is returned. Else the resolved type is returned. /// /// Type signature /// New which is never null unless /// is null public TypeSig Resolve(TypeSig typeSig) { if (typeSig is null) return null; var sig = typeSig; if (sig is GenericMVar genericMVar) { var newSig = methodArgsStack.Resolve(genericMVar.Number); if (newSig is null || newSig == sig) return sig; return newSig; } if (sig is GenericVar genericVar) { var newSig = typeArgsStack.Resolve(genericVar.Number); if (newSig is null || newSig == sig) return sig; return newSig; } return sig; } } }