public AffectedGraph GetCouplingGraphFor(string cacheName)
        {
            var            affected            = new List <ChangeContext>();
            var            graph               = new AffectedGraph();
            var            forwardCutOffPoints = new Dictionary <string, bool>();
            var            backCutOffPoints    = new Dictionary <string, bool>();
            TypeDefinition scope               = null;

            GetEfferentGraph(null, cacheName, forwardCutOffPoints, affected, graph, true, scope);
            WriteWalkerDebug("got " + affected + " nodes for " + cacheName, 0);
            var rets = affected.ForkAndJoinTo(_numthreads, x =>
            {
                FillAfferentGraph(x.Member, backCutOffPoints, graph, null, 0, null, false, new List <string>(), GenericContext.Empty(), false); //gets all tests Ca
                return(true);
            });

            return(graph);
        }
        private void RecurseAfferentCouplings(string fullName, int depth, Dictionary <string, bool> history, bool inInheritanceChain, TypeDefinition inheritedTypeContext, AffectedGraph graph, MemberReference parent, List <string> breadCrumbs, GenericContext genericContext)
        {
            var afferentEntry = _cache.TryGetAfferentCouplingNode(fullName);

            if (afferentEntry == null)
            {
                return;
            }
            genericContext.SetIndirectConstraintsOn(afferentEntry.MemberReference, parent, inInheritanceChain);
            if (!inInheritanceChain && genericContext.IsClear())
            {
                lock (history) //double lock, TryCutPointPrune already did this
                {
                    if (!history.ContainsKey(fullName))
                    {
                        history.Add(fullName, true);
                    }
                }
            }
            foreach (var current in afferentEntry.Couplings)
            {
                if (current.IgnoreWalk)
                {
                    continue;
                }
                var proposed = genericContext.GetGenericContextOf(current.ActualReference);
                if (!genericContext.CanTransitionTo(proposed))
                {
                    WriteWalkerDebug("Generics truncate", depth);
                    continue;
                }
                var newContext = genericContext.TransitionTo(proposed);
                FillAfferentGraph(current.To, history, graph, afferentEntry.MemberReference, depth + 1, inheritedTypeContext, inInheritanceChain && current.IsSelfCall, breadCrumbs, newContext, current.IsSelfCall);
            }
        }
        private void RecurseSynonyms(int depth, Dictionary <string, bool> history, TypeDefinition inheritedTypeContext, MethodDefinition currentDefinition, AffectedGraph graph, List <string> breadCrumbs, GenericContext genericContext)
        {
            var synonyms = SynonymFinder.FindSynonymsFor(currentDefinition);

            foreach (var current in synonyms)
            {
                var c = current as MethodDefinition;
                if (c == null)
                {
                    continue;            //shouldn't happen
                }
                if (!c.DeclaringType.IsInterface)
                {
                    FillAfferentGraph(current.GetCacheName(), history, graph, currentDefinition, depth + 1,
                                      inheritedTypeContext, true, breadCrumbs, genericContext, true); //always a base
                }
                else
                {
                    FillAfferentGraph(current.GetCacheName(), history, graph, currentDefinition, depth + 1,
                                      inheritedTypeContext, false, breadCrumbs, genericContext, false);
                }
            }
        }
        private void FillAfferentGraph(string fullName, Dictionary <string, bool> cutPoints, AffectedGraph graph, MemberReference parent, int depth, TypeDefinition inheritedTypeContext, bool inVirtual, List <string> breadCrumbs, GenericContext genericContext, bool inSelf)
        {
            WriteWalkerDebug(fullName, depth);
            if (TryBreadCrumbsPrune(fullName, depth, breadCrumbs))
            {
                if (parent != null)
                {
                    WriteWalkerDebug("truncating but adding connection to " + fullName, depth);
                    graph.AddConnection(parent.GetCacheName(), fullName, false);
                }
                return;
            }
            breadCrumbs.Add(fullName);
            if (TryCutPointPrune(fullName, depth, cutPoints))
            {
                if (parent != null)
                {
                    WriteWalkerDebug("bread crumbs truncating but adding connection to " + fullName, depth);
                    graph.AddConnection(parent.GetCacheName(), fullName, false);
                }
                return;
            }

            var efferentEntry = _cache.TryGetEfferentCouplingNode(fullName);
            var afferentEntry = _cache.TryGetEfferentCouplingNode(fullName);
            MethodDefinition currentDefinition = null;

            if (efferentEntry != null)
            {
                TypeReference parentType = null;
                if (parent != null)
                {
                    parentType = parent.DeclaringType;
                }
                var definition = efferentEntry.MemberReference.DeclaringType.ThreadSafeResolve();
                if (TryInterfacePrune(fullName, depth, breadCrumbs, efferentEntry, parentType, definition))
                {
                    return;
                }
                if (TryInheritancePrune(fullName, depth, breadCrumbs, inVirtual, definition, inheritedTypeContext))
                {
                    return;
                }
                inheritedTypeContext = GetNewTypeContext(inheritedTypeContext, definition);
                currentDefinition    = efferentEntry.MemberReference as MethodDefinition;
                if (currentDefinition != null)
                {
                    if (currentDefinition.DeclaringType == null)
                    {
                    }
                    if (parent is FieldReference && currentDefinition.IsConstructor)
                    {
                        breadCrumbs.Remove(fullName);
                        return;
                    }
                }
            }
            var touse = afferentEntry ?? efferentEntry;

            WriteWalkerDebug("adding node " + fullName, depth);
            var newnode = GetGraphNode(fullName, touse, parent == null, false);

            graph.AddNode(newnode);
            if (parent != null)
            {
                graph.AddConnection(parent.GetCacheName(), newnode.FullName, false);
            }
            if (currentDefinition != null)
            {
                RecurseSynonyms(depth, cutPoints, inheritedTypeContext, currentDefinition, graph, breadCrumbs, genericContext);
            }
            RecurseAfferentCouplings(fullName, depth, cutPoints, inVirtual, inheritedTypeContext, graph, parent, breadCrumbs, genericContext);
            breadCrumbs.Remove(fullName);
        }