private void BuildCacheFor(MethodBase m, MethodBaseCache.SpecialMethodEnum methodType, EventInfo ev, params MemberInfo[] addFor) { MethodBaseCache cacheForM = ((MethodBaseCache)GetMemberCache(m)); // check if method is used in a special context (property/event) if (cacheForM.MethodType == MethodBaseCache.SpecialMethodEnum.None && methodType != MethodBaseCache.SpecialMethodEnum.None) { cacheForM.MethodType = methodType; } cacheForM.SpecialReference = ev; BuildCacheFor(m, methodType, addFor); }
public MemberCache GetMemberCache(MemberInfo member) { lock (lockMethodCache) { MemberCache c; if (!memberCache.TryGetValue(new Member(member), out c)) { if (member is FieldInfo) { memberCache.Add(new Member(member), c = new FieldCache(member)); } else if (member is MethodBase) { memberCache.Add(new Member(member), c = new MethodBaseCache(member)); } else { memberCache.Add(new Member(member), c = new MemberCache(member)); } } return(c); } }
private void BuildCacheFor(MethodBase m, MethodBaseCache.SpecialMethodEnum methodType, params MemberInfo[] addFor) { MethodBaseCache cacheForM = ((MethodBaseCache)GetMemberCache(m)); // check if method is used in a special context (property/event) if (cacheForM.MethodType == MethodBaseCache.SpecialMethodEnum.None && methodType != MethodBaseCache.SpecialMethodEnum.None) { cacheForM.MethodType = methodType; } foreach (var p in m.GetParameters()) { if (!p.ParameterType.IsGenericParameter) { GetTypeCache(p.ParameterType).AddUsedBy(addFor); } } if (m is MethodInfo) { GetTypeCache(((MethodInfo)m).ReturnType).AddUsedBy(addFor); } try { foreach (var i in m.GetILInstructions()) { if (i.Operand is MemberInfo) { var cache = GetMemberCache((MemberInfo)i.Operand); foreach (var memberToAddFor in addFor) { cache.AddUsedBy(memberToAddFor, i.Offset); } cacheForM.AddUses((MemberInfo)i.Operand, i.Offset); if (i.Code == OpCodes.Call || i.Code == OpCodes.Callvirt) { ((MethodBaseCache)cache).AddCalledBy(addFor); } else if (i.Code == OpCodes.Stfld) { ((FieldCache)cache).AddAssignedBy(addFor); } else if (i.Code == OpCodes.Ldfld) { ((FieldCache)cache).AddReadBy(addFor); } else if (i.Code == OpCodes.Ldftn) // event wiring in c# uses ldftn to pass methods to the handler delegate constructor { // read as pointer, possibly for event if (i.Operand is MethodBase && i.Next.Code == OpCodes.Newobj && (i.Next.Next.Code == OpCodes.Callvirt || i.Next.Next.Code == OpCodes.Call)) { var addMethod = (MethodInfo)i.Next.Next.Operand; var addMethodCache = GetMemberCache(addMethod); MemberInfo source = null; if (i.Previous.Previous.Code == OpCodes.Ldfld) { source = (FieldInfo)i.Previous.Previous.Operand; } else if (i.Previous.Previous.Code == OpCodes.Call || i.Previous.Previous.Code == OpCodes.Callvirt) { source = (MethodInfo)i.Previous.Previous.Operand; } if (source != null) { // todo add event info to source } ((MethodBaseCache)cache).AddWiredForEvent(new WiredLookupEntry(addMethod, source)); ((MethodBaseCache)addMethodCache).AddWiresEvent(new WiredLookupEntry((MethodInfo)i.Operand, source)); } } else if (i.Code == OpCodes.Ldvirtftn) // VB.NET uses event wiring in a property setter { if (i.Operand is MethodBase && i.Next.Code == OpCodes.Newobj) { var nextnext = i.Next.Next; int idxOfEventLocal = -1; if (nextnext.Code == OpCodes.Stloc || nextnext.Code == OpCodes.Stloc_S) { idxOfEventLocal = (int)nextnext.Operand; } else if (nextnext.Code == OpCodes.Stloc_0) { idxOfEventLocal = 0; } else if (nextnext.Code == OpCodes.Stloc_1) { idxOfEventLocal = 1; } else if (nextnext.Code == OpCodes.Stloc_2) { idxOfEventLocal = 2; } else if (nextnext.Code == OpCodes.Stloc_3) { idxOfEventLocal = 3; } if (idxOfEventLocal != -1) { // go find the ldloc ILInstruction curInstr = i; while (curInstr != null) { if ((((curInstr.Code == OpCodes.Ldloc || curInstr.Code == OpCodes.Ldloc_S) && (int)curInstr.Operand == idxOfEventLocal) || (curInstr.Code == OpCodes.Ldloc_0 && idxOfEventLocal == 0) || (curInstr.Code == OpCodes.Ldloc_1 && idxOfEventLocal == 1) || (curInstr.Code == OpCodes.Ldloc_2 && idxOfEventLocal == 2) || (curInstr.Code == OpCodes.Ldloc_3 && idxOfEventLocal == 3)) && (curInstr.Next.Code == OpCodes.Call || curInstr.Next.Code == OpCodes.Callvirt) && curInstr.Previous.Code == OpCodes.Ldfld && ((MethodInfo)curInstr.Next.Operand).Name.StartsWith("add_")) { MemberInfo source = (MemberInfo)curInstr.Previous.Operand; var addMethod = (MethodInfo)curInstr.Next.Operand; var addMethodCache = GetMemberCache(addMethod); if (source != null) { // todo add event info to source } ((MethodBaseCache)cache).AddWiredForEvent(new WiredLookupEntry(addMethod, source)); ((MethodBaseCache)addMethodCache).AddWiresEvent(new WiredLookupEntry((MethodInfo)i.Operand, source)); break; } curInstr = curInstr.Next; } } } } else if (i.Code == OpCodes.Newobj) { GetTypeCache(((ConstructorInfo)i.Operand).DeclaringType).AddCreatedBy(addFor); } } if (i.Code == OpCodes.Ldstr) { cacheForM.AddUsedString((string)i.Operand); } } } catch (Exception ex) { Console.WriteLine("Unable to build analysis cache for " + m.ToSignatureString() + ", error: " + ex.GetType().FullName + " - " + ex.Message); } }