private static IEnumerable <SuspectSet> FindCallersCallingAtLeastNSameMethods(CallerAndMembersUsed[] callersSuspect, HashSet <PairOfMethodCallers> pairsOfCallersAlreadyTreated, int N) { Debug.Assert(callersSuspect != null); Debug.Assert(callersSuspect.Length >= 2); Debug.Assert(pairsOfCallersAlreadyTreated != null); var suspectSetsWith2Callers = new List <SuspectSet>(); MembersUsedIntersectionComputer <CallerAndMembersUsed> .Go(callersSuspect, N, // This lambda is called to know if a pair of CallerAndMembersUsed should be treated or not. (callerI, callerJ) => { var pair = new PairOfMethodCallers(callerI.MethodCaller, callerJ.MethodCaller); // Avoid treating a pair of method callers already reated! if (pairsOfCallersAlreadyTreated.Contains(pair)) { return(false); } pairsOfCallersAlreadyTreated.Add(pair); return(true); }, // This lambda is called when a merge should occurs. (callerI, callerJ, methodCalledsIntersection, fieldsReadIntersection, fieldsAssignedIntersection) => { // Merge suspectSetI and suspectSetJ var suspectSet = new SuspectSet(new List <IMethod> { callerI.MethodCaller, callerJ.MethodCaller }, methodCalledsIntersection, fieldsReadIntersection, fieldsAssignedIntersection); suspectSetsWith2Callers.Add(suspectSet); return(false); // <-- This provoques continue current loop }); return(suspectSetsWith2Callers); }
// // Inputed suspectSets that shares a common caller, all have 2 callers. // private static IEnumerable <SuspectSet> MergeSuspectSetsSharingACommonCaller(IList <SuspectSet> suspectSetsSharingACommonCaller, int N) { Debug.Assert(suspectSetsSharingACommonCaller != null); if (suspectSetsSharingACommonCaller.Count == 1) { return(suspectSetsSharingACommonCaller); } var suspectSetsMergedFinal = new List <SuspectSet>(); // suspectSetsMergedCurrent => i.e merged during the current iteration List <SuspectSet> suspectSetsMergedCurrent; // suspectSetsMergedPrevious => i.e merged during previous iteration SuspectSet[] suspectSetsMergedPrevious = suspectSetsSharingACommonCaller.ToArray(); // // Iteratively merge suspectSets when possible, until no more suspectSets can be merged. // do { suspectSetsMergedCurrent = new List <SuspectSet>(); // Optimization: use a hashset to have a constant time remove. var suspectSetsNotMergeableAnymore = suspectSetsMergedPrevious.ToHashSet(); // // Try to merge suspectSets merged during the previous iteration. // MembersUsedIntersectionComputer <SuspectSet> .Go(suspectSetsMergedPrevious, N, // Always see if a pair of SuspectSet can be merged (callerI, callerJ) => true, // This lambda is called when a merge should occurs. (suspectSetI, suspectSetJ, methodCalledsIntersection, fieldsReadIntersection, fieldsAssignedIntersection) => { // Merge suspectSetI and suspectSetJ var callersUnion = suspectSetI.MethodsCaller.Union(suspectSetJ.MethodsCaller).ToArray(); suspectSetsMergedCurrent.Add(new SuspectSet(callersUnion, methodCalledsIntersection, fieldsReadIntersection, fieldsAssignedIntersection)); suspectSetsNotMergeableAnymore.Remove(suspectSetI); suspectSetsNotMergeableAnymore.Remove(suspectSetJ); return(true); // <-- This provoques break current loop }); suspectSetsMergedPrevious = suspectSetsMergedCurrent.ToArray(); suspectSetsMergedFinal.AddRange(suspectSetsNotMergeableAnymore); } while (suspectSetsMergedCurrent.Count > 0); return(suspectSetsMergedFinal); }