public void TestEquals_EmptyNames() { var tx = new MetadataTokenName { Name = "", Id = 4451, DeclTypeId = 3322, OwnAsmIdx = 0, RslvAsmIdx = 0 }; var ty = new MetadataTokenName { Name = "", Id = 1544, DeclTypeId = 2233, OwnAsmIdx = 1, RslvAsmIdx = 1 }; var testSubject = new MetadataTokenNameComparer(); var testResult = testSubject.Equals(tx, ty); Assert.IsTrue(testResult); }
private static MetadataTokenName AccumulateItems(MetadataTokenName something) { if (something == null) { return(null); } _accum.Push(something); return(something); }
/// <summary> /// An optional invocation, the caller could just invoke the ReassignAllInterfaceTokens /// on the <see cref="subjectNames"/>; however, for some assemblies this takes a long time. /// This option does the same thing only on a remote process with a progress indicator. /// </summary> public TokenReassignResponse ReassignTokenNames(MetadataTokenName subjectNames, MetadataTokenName foreignNames, MetadataTokenType foreignTokenTypes, string rootAssemblyName = "") { _reassignTokenNamesCmd.Request = new TokenReassignRequest { SubjectTokenNames = subjectNames, ForeignTokenNames = foreignNames, ForeignTokenTypes = foreignTokenTypes, AsmName = rootAssemblyName }; return(_reassignTokenNamesCmd.Receive(null)); }
public static void SaveToFile(string filePath, MetadataTokenName rootTokenName) { if (rootTokenName?.Items == null || !rootTokenName.Items.Any()) { return; } var json = JsonConvert.SerializeObject(rootTokenName, Formatting.None, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); File.WriteAllText(filePath, json); }
public void TestReassignAnyItemsByName() { var testInput = GetTestMetadataTokenNameTree(); var testSearchFor = new MetadataTokenName { Name = "(I) [2,0]" }; var testReplacement = new MetadataTokenName { Name = "*new* (I) [2,0]", Items = new[] { new MetadataTokenName { Name = "*added* [2,0,0]" }, new MetadataTokenName { Name = "*added* [2,0,1]", Items = new [] { new MetadataTokenName { Name = "*added* [2,0,1,0]" } } } } }; testInput.ReassignAnyItemsByName(testSearchFor, testReplacement); var testResultItem = new MetadataTokenName(); Func <MetadataTokenName, bool> searchFor = (v) => string.Equals(v?.Name, testReplacement.Name); Func <MetadataTokenName, MetadataTokenName> getMatch = (v) => testResultItem = v; testInput.IterateTree(searchFor, getMatch); Assert.IsNotNull(testResultItem); Assert.AreEqual("*new* (I) [2,0]", testResultItem.Name); Assert.IsNotNull(testResultItem.Items); Assert.AreEqual("*added* [2,0,0]", testResultItem.Items[0].Name); Assert.AreEqual("*added* [2,0,1]", testResultItem.Items[1].Name); Assert.IsNotNull(testResultItem.Items[1].Items); Assert.AreEqual("*added* [2,0,1,0]", testResultItem.Items[1].Items[0].Name); }
public void TestEquals_SameVariable() { var tx = new MetadataTokenName { Name = "", Id = 4451, DeclTypeId = 3322, OwnAsmIdx = 0, RslvAsmIdx = 0 }; var ty = tx; var testSubject = new MetadataTokenNameComparer(); var testResult = testSubject.Equals(tx, ty); Assert.IsTrue(testResult); }
/// <summary> /// Locates the <see cref="CgMember"/> who matches <see cref="tokenName"/>. /// </summary> /// <param name="tokenName"></param> /// <returns></returns> public CgMember FindCgMemberByTokenName(MetadataTokenName tokenName) { if (tokenName == null) { return(null); } var byToken = FindCgMember(tokenName.Id); if (byToken != null) { return(byToken); } if (string.IsNullOrWhiteSpace(tokenName.Name)) { return(null); } var methodName = MetadataTokenName.ParseMethodNameFromTokenName(tokenName.Name); var argNames = MetadataTokenName.ParseArgsFromTokenName(tokenName.Name); return(FindCgMember(methodName, argNames)); }
public static MetadataTokenName GetTestMetadataTokenNameTree() { /* * root * o * | * o-----------o-+----------o * (A) | | * | | * o-----------o-------o-+----o o--+------o * | (C) | (H) (I) | * | | | * o o------o-+----o o-----+------o * | | (F) | | (M) * | | | | * o o--+---o o o--+-o----o * (B) (D) (E) (G) (J) (K) (L) * */ var testInput = new MetadataTokenName { Name = "root", Items = new[] { new MetadataTokenName { Name = "(A) [0]" }, new MetadataTokenName { Name = "[1]", Items = new [] { new MetadataTokenName { Name = "[1,0]", Items = new [] { new MetadataTokenName { Name = "[1,0,0]", Items = new [] { new MetadataTokenName { Name = "(B) [1,0,0,0]" } } } } }, new MetadataTokenName { Name = "(C) [1,1]" }, new MetadataTokenName { Name = "[1,2]", Items = new [] { new MetadataTokenName { Name = "[1,2,0]", Items = new [] { new MetadataTokenName { Name = "(D) [1,2,0,0]" }, new MetadataTokenName { Name = "(E) [1,2,0,1]" } } }, new MetadataTokenName { Name = "(F) [1,2,1]" }, new MetadataTokenName { Name = "[1,2,2]", Items = new [] { new MetadataTokenName { Name = "(G) [1,2,2,0]" } } } } }, new MetadataTokenName { Name = "(H) [1,3]" } } }, new MetadataTokenName { Name = "[2]", Items = new [] { new MetadataTokenName { Name = "(I) [2,0]" }, new MetadataTokenName { Name = "[2,1]", Items = new [] { new MetadataTokenName { Name = "[2,1,0]", Items = new [] { new MetadataTokenName { Name = "(J) [2,1,0,0]" }, new MetadataTokenName { Name = "(K) [2,1,0,1]" }, new MetadataTokenName { Name = "(L) [2,1,0,2]" }, } }, new MetadataTokenName { Name = "(M) [2,1,1]" } } } } } } }; return(testInput); }
/// <summary> /// Intended for resolving method calls of types defined in another assembly. /// </summary> /// <param name="owningAsm"></param> /// <param name="tokenName">The name as drafted from <see cref="AssemblyAnalysis.ConvertToMetadataTokenName"/></param> /// <param name="mi"></param> /// <param name="msgOut">Intended for debug trace from the Console.</param> /// <returns></returns> internal bool TryResolveRtMemberInfo(Assembly owningAsm, string tokenName, out MemberInfo mi, StringBuilder msgOut = null) { //default the out variable mi = null; //expect token name to match naming given herein if (String.IsNullOrWhiteSpace(tokenName)) { if (msgOut != null) { msgOut.Append(", Message:'the token name is null'"); } return(false); } if (!tokenName.Contains(Constants.TYPE_METHOD_NAME_SPLIT_ON)) { if (msgOut != null) { msgOut.AppendFormat(", Message:'[{0}] does not contain {1}'", tokenName, Constants.TYPE_METHOD_NAME_SPLIT_ON); } } if (owningAsm == null) { if (msgOut != null) { msgOut.Append(", Message:'the owning assembly is null'"); } return(false); } var assemblyName = owningAsm.GetName().Name; var typeName = MetadataTokenName.CtorTypeNameFromTokenName(tokenName, assemblyName); if (String.IsNullOrWhiteSpace(typeName)) { if (msgOut != null) { msgOut.Append(", Message:'could not parse type name'"); } return(false); } Type asmType = null; try { //framework throwing null-ref ex despite null checks asmType = owningAsm.NfGetType(typeName, false, _myProgram.LogFile); } catch { if (msgOut != null) { msgOut.Append(", Message:'Assembly.GetType threw exception'"); } return(false); } if (asmType == null) { if (msgOut != null) { msgOut.AppendFormat(", Message:'assembly {0} could not resolve {1}'", assemblyName, typeName); } return(false); } var methodName = MetadataTokenName.ParseMethodNameFromTokenName(tokenName); if (String.IsNullOrWhiteSpace(methodName)) { if (msgOut != null) { msgOut.Append(", Message:'could not parse method name'"); } return(false); } MethodInfo methodInfo = null; //try easiest first try { methodInfo = asmType.NfGetMethod(methodName, NfSettings.DefaultFlags); } catch (AmbiguousMatchException) { }//is overloaded //try it the formal way if (methodInfo == null) { var args = MetadataTokenName.ParseArgsFromTokenName(tokenName).ToArray(); var argTypes = args.Length <= 0 ? Type.EmptyTypes : args.Select(Type.GetType).Where(x => x != null).ToArray(); //there must be a one-for-one match of string names to first-class types if (args.Length == argTypes.Length) { methodInfo = asmType.NfGetMethod(methodName, NfSettings.DefaultFlags, null, argTypes, null, false, _myProgram.LogFile); } } //try it the very slow but certain way if (methodInfo == null) { var methodInfos = asmType.NfGetMethods(NfSettings.DefaultFlags, false, _myProgram.LogFile); if (methodInfos.Length <= 0) { if (msgOut != null) { msgOut.AppendFormat(", Assembly:'{0}'\n", assemblyName); msgOut.AppendFormat(", Type:'{0}'\n", typeName); msgOut.Append(", Message:'does not have any methods'"); } return(false); } foreach (var info in methodInfos) { var asTokenName = AssemblyAnalysis.ConvertToMetadataTokenName(info, _myProgram.AsmIndicies, IsIgnore, _myProgram.LogFile); if (asTokenName == null || string.IsNullOrWhiteSpace(asTokenName.Name)) { continue; } if (string.Equals(asTokenName.Name, tokenName)) { methodInfo = info; break; } } } if (methodInfo == null) { if (msgOut != null) { msgOut.AppendFormat(", Assembly:'{0}'\n", assemblyName); msgOut.AppendFormat(", Type:'{0}'\n", typeName); msgOut.AppendFormat(", Method:'{0}'\n", methodName); msgOut.Append(", Message:'was not found'"); } return(false); } mi = methodInfo; return(true); }
/// <summary> /// Attempts to resolve <see cref="tokenId"/> to a <see cref="MetadataTokenName"/> /// </summary> /// <param name="resolvesWith"></param> /// <param name="tokenId"></param> /// <param name="tokenName"></param> /// <param name="msgOut">Intended for debug trace from the Console.</param> /// <returns></returns> internal bool ResolveSingleTokenName(Assembly resolvesWith, MetadataTokenId tokenId, out MetadataTokenName tokenName, StringBuilder msgOut = null) { tokenName = null; if (tokenId.Id == 0) { if (msgOut != null) { msgOut.Append(", Message:'the token id is zero'"); } return(false); } if (_myProgram.TokenId2NameCache.ContainsKey(tokenId)) { tokenName = _myProgram.TokenId2NameCache[tokenId]; if (msgOut != null) { msgOut.Append(", Message:'token previously resolved'"); } return(true); } if (resolvesWith == null) { if (msgOut != null) { msgOut.Append(string.Format(", Message:'resolve assembly idx {0} has no match'", tokenId.RslvAsmIdx)); } return(false); } MemberInfo mi; var rtMiRslt = false; rtMiRslt = TryResolveRtMemberInfo(resolvesWith.ManifestModule, tokenId, out mi, msgOut); if (!rtMiRslt) { return(false); } if (mi == null) { return(false); } tokenName = AssemblyAnalysis.ConvertToMetadataTokenName(mi, _myProgram.AsmIndicies, IsIgnore, _myProgram.LogFile); if (tokenName == null) { if (msgOut != null) { msgOut.Append(", Message:'could not construct a token name'"); } return(false); } tokenName.Id = tokenId.Id; tokenName.RslvAsmIdx = tokenId.RslvAsmIdx; tokenName.DeclTypeId = mi.DeclaringType?.MetadataToken ?? 0; return(true); }
/// <summary> /// Helper method which resolves the assembly using the <see cref="tokenId"/> RslvAsmIdx. /// </summary> /// <param name="tokenId"></param> /// <param name="tokenName"></param> /// <param name="msgOut">Intended for debug trace from the Console.</param> /// <returns></returns> internal bool ResolveSingleTokenName(MetadataTokenId tokenId, out MetadataTokenName tokenName, StringBuilder msgOut = null) { var manifestAsm = _myProgram.AsmIndicies.GetAssemblyByIndex(tokenId.RslvAsmIdx); return(ResolveSingleTokenName(manifestAsm, tokenId, out tokenName, msgOut)); }
public override byte[] Execute(byte[] arg) { MyProgram.PrintToConsole(); MyProgram.PrintToConsole($"{nameof(GetTokenNames)} invoked"); MyProgram.ProgressMessageState = null; try { var myIaaProgram = ((IaaProgram)MyProgram); if (myIaaProgram.AsmInited != true) { MyProgram.PrintToConsole("no assemblies are loaded - call GetAsmIndices"); return(JsonEncodedResponse( new TokenNameResponse { Msg = "no assemblies are loaded - call GetAsmIndices", St = MetadataTokenStatus.Error })); } var json = Encoding.UTF8.GetString(arg); var rqst = JsonConvert.DeserializeObject <TokenNameRequest>(json); var tokens = rqst.Tokens ?? myIaaProgram.TokenIdResponse?.Tokens; if (tokens == null || tokens.Length <= 0) { return(JsonEncodedResponse(new TokenNameResponse { Msg = "parse failed", St = MetadataTokenStatus.Error })); } var names = myIaaProgram.UtilityMethods.ResolveAllTokenNames(tokens); Console.Write('\n'); var tokenNameRspn = new TokenNameResponse { Names = names.ToArray() }; if (rqst.MapFullCallStack && myIaaProgram.TokenTypeResponse != null && myIaaProgram.TokenIdResponse != null) { var nameRoot = tokenNameRspn.GetAsRoot(); var tokenRoot = myIaaProgram.TokenIdResponse.GetAsRoot(); var typeRoot = myIaaProgram.TokenTypeResponse.GetAsRoot(); var asmRspn = myIaaProgram.AsmIndicies; var fullCallStack = MetadataTokenName.BuildMetadataTokenName(nameRoot, tokenRoot, asmRspn, typeRoot, MyProgram.PrintToConsole); if (fullCallStack?.Items != null) { tokenNameRspn.Names = fullCallStack.Items; } } myIaaProgram.TokenNameResponse = tokenNameRspn; return(JsonEncodedResponse(tokenNameRspn)); } catch (Exception ex) { MyProgram.PrintToConsole(ex); return(JsonEncodedResponse(new TokenNameResponse { Msg = string.Format(ex.Message), St = MetadataTokenStatus.Error })); } }
/// <summary> /// Transforms a <see cref="MemberInfo"/> into a <see cref="MetadataTokenName"/> /// getting as much info as possible depending on which /// child-type the <see cref="mi"/> resolves to. /// </summary> /// <param name="mi"></param> /// <param name="indicies"> /// optional parameter, used to abbreviate the name removing the redundant part shared /// by both assembly and namespace. /// </param> /// <param name="isIgnore">optional f(x) pointer for calling assembly to specify some additional rules by token name</param> /// <param name="logFile"> /// optional, the path to a log file where any assembly, type, member, method, etc. loader exceptions will be written. /// </param> /// <param name="truncateAsmPartOfName"> /// Optional switch to reduce the member name to only what is original. The prefixed portion can be restored based on the Owning Assembly's name. /// </param> /// <returns></returns> public static MetadataTokenName ConvertToMetadataTokenName(MemberInfo mi, AsmIndexResponse indicies, Func <string, bool> isIgnore, string logFile = null, bool truncateAsmPartOfName = true) { if (mi == null) { return(null); } var localIsIgnore = isIgnore ?? (s => false); var localIndicies = indicies ?? new AsmIndexResponse { Asms = new MetadataTokenAsm[0] }; var tokenName = new MetadataTokenName { Name = mi.Name, Label = mi.GetType().Name, DeclTypeId = mi.DeclaringType?.MetadataToken ?? 0, Id = mi.MetadataToken }; string asmQualName; string asmName; string expandedName; var type = mi as Type; if (type != null) { asmQualName = type.Assembly.GetName().FullName; //do not send back GAC asm's unless asked if (localIsIgnore(asmQualName)) { return(null); } var t = localIndicies.Asms.FirstOrDefault( x => String.Equals(x.AssemblyName, type.Assembly.GetName().FullName, StringComparison.OrdinalIgnoreCase)); if (t == null) { return(null); } asmName = type.Assembly.GetName().Name; expandedName = !string.IsNullOrEmpty(asmName) ? (type.FullName ?? UNKNOWN_NAME_SUB).Replace($"{asmName}", string.Empty) : type.FullName; if (!string.Equals(expandedName, tokenName.Name, StringComparison.OrdinalIgnoreCase)) { tokenName.Name = expandedName; } tokenName.OwnAsmIdx = t.IndexId; tokenName.IsAmbiguous = type.IsInterface || type.IsAbstract; return(tokenName); } if (mi.DeclaringType == null) { return(tokenName); } asmQualName = mi.DeclaringType.Assembly.GetName().FullName; //do not send back GAC asm's unless asked if (localIsIgnore(asmQualName) || localIsIgnore(mi.DeclaringType.FullName)) { return(null); } var f = localIndicies.Asms.FirstOrDefault( x => string.Equals(x.AssemblyName, mi.DeclaringType.Assembly.GetName().FullName, StringComparison.OrdinalIgnoreCase)); if (f == null) { return(null); } asmName = mi.DeclaringType.Assembly.GetName().Name; expandedName = !string.IsNullOrEmpty(asmName) && truncateAsmPartOfName ? (mi.DeclaringType.FullName ?? UNKNOWN_NAME_SUB).Replace($"{asmName}", string.Empty) : mi.DeclaringType.FullName; if (!string.Equals(expandedName, tokenName.Name, StringComparison.OrdinalIgnoreCase)) { tokenName.Name = $"{expandedName}{Constants.TYPE_METHOD_NAME_SPLIT_ON}{tokenName.Name}"; } tokenName.OwnAsmIdx = f.IndexId; var mti = mi as MethodInfo; if (mti == null) { return(tokenName); } tokenName.IsAmbiguous = mti.IsAbstract; var mtiParams = mti.NfGetParameters(false, logFile); if (mtiParams.Length <= 0) { tokenName.Name = $"{tokenName.Name}()"; return(tokenName); } var paramNames = new List <string>(); foreach (var param in mtiParams) { var workingName = param.ParameterType.FullName ?? UNKNOWN_NAME_SUB; if (!param.ParameterType.IsGenericType) { paramNames.Add(workingName); continue; } var paramsGen = param.ParameterType.NfGetGenericArguments(false, logFile); foreach (var genParam in paramsGen) { var asmGenParamName = genParam.AssemblyQualifiedName; if (string.IsNullOrWhiteSpace(asmGenParamName)) { continue; } workingName = workingName.Replace("[" + asmGenParamName + "]", genParam.FullName); } paramNames.Add(workingName); } tokenName.Name = $"{tokenName.Name}({string.Join(",", paramNames)})"; return(tokenName); }
/// <summary> /// Transforms a <see cref="MemberInfo"/> into a <see cref="MetadataTokenName"/> /// getting as much info as possiable depending on which /// child-type the <see cref="mi"/> resolves to. /// </summary> /// <param name="mi"></param> /// <param name="indicies"> /// optional parameter, used to abbreviate the name removing the redundant part shared /// by both assembly and namespace. /// </param> /// <param name="isIgnore">optional f(x) pointer for calling assembly to specify some additional rules by token name</param> /// <returns></returns> public static MetadataTokenName ConvertToMetadataTokenName(MemberInfo mi, AsmIndicies indicies, Func<string, bool> isIgnore) { if (mi == null) return null; var localIsIgnore = isIgnore ?? (s => false); var localIndicies = indicies ?? new AsmIndicies { Asms = new MetadataTokenAsm[0] }; var tokenName = new MetadataTokenName { Name = mi.Name, Label = mi.GetType().Name }; string asmQualName; string asmName; string expandedName; var type = mi as Type; if (type != null) { asmQualName = type.Assembly.GetName().FullName; //do not send back GAC asm's unless asked if (localIsIgnore(asmQualName)) return null; var t = localIndicies.Asms.FirstOrDefault( x => String.Equals(x.AssemblyName, type.Assembly.GetName().FullName, StringComparison.OrdinalIgnoreCase)); if (t == null) return null; asmName = type.Assembly.GetName().Name; expandedName = !string.IsNullOrEmpty(asmName) ? type.FullName.Replace($"{asmName}", string.Empty) : type.FullName; if (!string.Equals(expandedName, tokenName.Name, StringComparison.OrdinalIgnoreCase)) tokenName.Name = expandedName; tokenName.OwnAsmIdx = t.IndexId; return tokenName; } if (mi.DeclaringType == null) return tokenName; asmQualName = mi.DeclaringType.Assembly.GetName().FullName; //do not send back GAC asm's unless asked if (localIsIgnore(asmQualName) || localIsIgnore(mi.DeclaringType.FullName)) return null; var f = localIndicies.Asms.FirstOrDefault( x => string.Equals(x.AssemblyName, mi.DeclaringType.Assembly.GetName().FullName, StringComparison.OrdinalIgnoreCase)); if (f == null) return null; asmName = mi.DeclaringType.Assembly.GetName().Name; expandedName = !string.IsNullOrEmpty(asmName) ? mi.DeclaringType.FullName.Replace($"{asmName}", string.Empty) : mi.DeclaringType.FullName; if (!string.Equals(expandedName, tokenName.Name, StringComparison.OrdinalIgnoreCase)) tokenName.Name = $"{expandedName}{Constants.TYPE_METHOD_NAME_SPLIT_ON}{tokenName.Name}"; tokenName.OwnAsmIdx = f.IndexId; var mti = mi as MethodInfo; if (mti == null) return tokenName; var mtiParams = mti.GetParameters(); if (mtiParams.Length <= 0) { tokenName.Name = $"{tokenName.Name}()"; return tokenName; } var paramNames = new List<string>(); foreach (var param in mtiParams) { var workingName = param.ParameterType.FullName; if (!param.ParameterType.IsGenericType) { paramNames.Add(workingName); continue; } var paramsGen = param.ParameterType.GetGenericArguments(); foreach (var genParam in paramsGen) { var asmGenParamName = genParam.AssemblyQualifiedName; if (string.IsNullOrWhiteSpace(asmGenParamName)) continue; workingName = workingName.Replace("[" + asmGenParamName + "]", genParam.FullName); } paramNames.Add(workingName); } tokenName.Name = $"{tokenName.Name}({string.Join(",", paramNames)})"; return tokenName; }
/// <summary> /// Resolves the outbound call stack for the given <see cref="token"/> /// </summary> /// <param name="token"></param> /// <param name="depth"></param> /// <param name="stackTrc">For detecting recursive call patterns</param> /// <param name="msgOut">For getting details on recursion.</param> internal void ResolveCallOfCall(MetadataTokenId token, ref int depth, Stack <MetadataTokenId> stackTrc, StringBuilder msgOut) { if (msgOut != null) { if (depth > 0) { msgOut.Append(new string(' ', depth)); } msgOut.AppendFormat("Depth:{0}", depth); msgOut.AppendFormat(", Token:{0}.0x{1}", token.RslvAsmIdx, token.Id.ToString("X4")); } //detect if we are in a recursive call if (stackTrc.Any(x => x.Equals(token))) { if (msgOut != null) { msgOut.AppendLine(", Message:'present in stack trace'"); } return; } stackTrc.Push(new MetadataTokenId { Id = token.Id, RslvAsmIdx = token.RslvAsmIdx }); //increment the current depth depth += 1; //abort if max depth has been reached if (depth > ((IaaProgram)MyProgram).MaxRecursionDepth) { depth -= 1; MyProgram.PrintToConsole( String.Format("Max Recursion Depth @ {0}.{1}\n", token.RslvAsmIdx, token.Id)); if (msgOut != null) { msgOut.AppendLine(", Message:'max recursion depth'"); } return; } //when there are already Items then leave them as is if (token.Items != null && token.Items.Length > 0) { depth -= 1; if (msgOut != null) { msgOut.AppendLine(", Message:'Items already present'"); } return; } //don't waste clock cycles on Ignore types if (((IaaProgram)MyProgram).DisolutionCache.Contains(token)) { depth -= 1; if (msgOut != null) { msgOut.AppendLine(", Message:'token in DisolutionCache'"); } return; } //resolve token to name MetadataTokenName tokenName = null; if (((IaaProgram)MyProgram).TokenId2NameCache.ContainsKey(token)) { tokenName = ((IaaProgram)MyProgram).TokenId2NameCache[token]; } else { // the token must be resolvable with the its manifest module var resolveRslt = ((IaaProgram)MyProgram).UtilityMethods.ResolveSingleTokenName(token, out tokenName, msgOut); if (!resolveRslt || tokenName == null) { ((IaaProgram)MyProgram).DisolutionCache.Add(token); depth -= 1; if (msgOut != null) { msgOut.AppendLine(", Message:'ResolveSingleTokenName failed'"); } return; } ((IaaProgram)MyProgram).TokenId2NameCache.Add(token, tokenName); } //only proceed to find calls of calls, types are resolved elsewhere if (!tokenName.IsMethodName()) { depth -= 1; if (msgOut != null) { msgOut.AppendLine(", Message:'token is not a method'"); } return; } //match is on Asm Name, not type nor member name var owningAsmName = ((IaaProgram)MyProgram).AsmIndicies.Asms.FirstOrDefault(x => x.IndexId == tokenName.OwnAsmIdx); if (owningAsmName == null) { ((IaaProgram)MyProgram).DisolutionCache.Add(token); depth -= 1; if (msgOut != null) { msgOut.AppendLine(string.Format(", Message:'owning assembly idx {0} has no match'", tokenName.OwnAsmIdx)); } return; } //check for match of asm name to user defined regex if (!Regex.IsMatch(owningAsmName.AssemblyName, ((IaaProgram)MyProgram).AssemblyNameRegexPattern)) { ((IaaProgram)MyProgram).DisolutionCache.Add(token); if (msgOut != null) { msgOut.AppendLine(string.Format(", Message:'assembly name [{1}] does not match regex [{0}]'", ((IaaProgram)MyProgram).AssemblyNameRegexPattern, owningAsmName.AssemblyName)); } depth -= 1; return; } //resolve token to runtime member info MemberInfo mi; var rtMiRslt = ((IaaProgram)MyProgram).UtilityMethods.TryResolveRtMemberInfo(((IaaProgram)MyProgram).AsmIndicies.GetAssemblyByIndex(owningAsmName.IndexId), tokenName.Name, out mi, msgOut); if (!rtMiRslt) { ((IaaProgram)MyProgram).DisolutionCache.Add(token); depth -= 1; return; } //get the token as it is called in its own assembly var r = AssemblyAnalysis.GetMetadataToken(mi, true, tokenName.OwnAsmIdx); if (stackTrc.Any(x => x.Equals(r))) { depth -= 1; token.IsByRef = 1; if (msgOut != null) { msgOut.AppendLine(string.Format(", Message:'name resolved token id {0},{1} found in stack trace'", r.RslvAsmIdx, r.Id.ToString("X4"))); } return; } //this token differs from the method arg 'token' stackTrc.Push(new MetadataTokenId { Id = r.Id, RslvAsmIdx = r.RslvAsmIdx }); //unwind when its a terminal token if (r.Items == null || r.Items.Length <= 0) { depth -= 1; if (msgOut != null) { msgOut.AppendLine(string.Format(", Message:'name resolved token id {0},{1} is a terminal node'", r.RslvAsmIdx, r.Id.ToString("X4"))); } return; } //these token ids are only resolvable to the asm who owns MemberInfo(mi) token.Items = r.Items; //recurse each of these calls-of-calls[...]-of-calls foreach (var iToken in token.Items) { ResolveCallOfCall(iToken, ref depth, stackTrc, msgOut); } depth -= 1; }
/// <summary> /// Locates the <see cref="CgMember"/> in <see cref="Methods"/> who matches <see cref="tokenName"/>. /// </summary> /// <param name="tokenName"></param> /// <returns></returns> public CgMember FindCgMethodByTokenName(MetadataTokenName tokenName) { if (tokenName == null) return null; if (string.IsNullOrWhiteSpace(tokenName.Name)) return null; if (!tokenName.IsMethodName()) return null; var methodName = AssemblyAnalysis.ParseMethodNameFromTokenName(tokenName.Name); if (string.IsNullOrWhiteSpace(methodName)) return null; string isPropName; if (NfTypeName.IsClrMethodForProperty(tokenName.Name, out isPropName)) { methodName = isPropName; var propMatches = Properties.Where(p => string.Equals(p.Name, methodName)).ToArray(); if (propMatches.Length >= 1) return propMatches.First(); } var matches = Methods.Where(x => string.Equals(x.Name, methodName)).ToArray(); if (matches.Length <= 0) return null; if (matches.Length == 1) return matches.First(); //attempt to match on arg count first var argNames = AssemblyAnalysis.ParseArgsFromTokenName(tokenName.Name); var argCount = argNames == null ? 0 : argNames.Length; matches = Methods.Where(x => x.Args.Count == argCount).ToArray(); if (matches.Length <= 0) return null; if (matches.Length == 1) return matches.First(); if (argNames == null) return null; //attempt to match by args names var argNamesLikeThese = argNames.Select(x => Settings.LangStyle.TransformClrTypeSyntax(x)); foreach (var match in matches) { if (match.Args.All(nfArg => argNamesLikeThese.Any(token => string.Equals(nfArg.ArgType, token)))) return match; } return null; }
/// <summary> /// Attempts to resolve <see cref="tokenId"/> to a <see cref="MetadataTokenName"/> /// </summary> /// <param name="resolvesWith"></param> /// <param name="tokenId"></param> /// <param name="tokenName"></param> /// <param name="msgOut">Inteneded for debug trace from the Console.</param> /// <returns></returns> internal bool ResolveSingleTokenName(Assembly resolvesWith, MetadataTokenId tokenId, out MetadataTokenName tokenName, StringBuilder msgOut = null) { tokenName = null; if (tokenId.Id == 0) { if (msgOut != null) msgOut.Append(", Message:'the token id is zero'"); return false; } if (_myProgram.TokenId2NameCache.ContainsKey(tokenId)) { tokenName = _myProgram.TokenId2NameCache[tokenId]; if (msgOut != null) msgOut.Append(", Message:'token previously resolved'"); return true; } if (resolvesWith == null) { if (msgOut != null) msgOut.Append(string.Format(", Message:'resolve assembly idx {0} has no match'", tokenId.RslvAsmIdx)); return false; } MemberInfo mi; var rtMiRslt = false; rtMiRslt = TryResolveRtMemberInfo(resolvesWith.ManifestModule, tokenId, out mi, msgOut); if (!rtMiRslt) { return false; } if (mi == null) { return false; } tokenName = AssemblyAnalysis.ConvertToMetadataTokenName(mi, _myProgram.AsmIndicies, IsIgnore); if (tokenName == null) { if (msgOut != null) msgOut.Append(", Message:'could not construct a token name'"); return false; } tokenName.Id = tokenId.Id; tokenName.RslvAsmIdx = tokenId.RslvAsmIdx; return true; }
/// <summary> /// Helper method which resolves the assembly using the <see cref="tokenId"/> RslvAsmIdx. /// </summary> /// <param name="tokenId"></param> /// <param name="tokenName"></param> /// <param name="msgOut">Inteneded for debug trace from the Console.</param> /// <returns></returns> internal bool ResolveSingleTokenName(MetadataTokenId tokenId, out MetadataTokenName tokenName, StringBuilder msgOut = null) { var manifestAsm = _myProgram.AsmIndicies.GetAssemblyByIndex(tokenId.RslvAsmIdx); return ResolveSingleTokenName(manifestAsm, tokenId, out tokenName, msgOut); }