private List <MethodCall> Analyze(IEnumerable <Node> relevantNodes, InterfaceImplementationsMap interfaceImplementationsMap, List <Type> analyzed, List <Type> callers) { var calls = callers.AsParallel() .SelectMany(t => GetCalledMethods(t) .Where(r => CoveredByAssemblyGraph(relevantNodes, r.To.DeclaringType)) .SelectMany(x => interfaceImplementationsMap.ResolveInterface(x))) .ToList(); var unknownTypes = calls.AsParallel() .Select(e => e.To.DeclaringType) .Distinct() .ToList() .Except(analyzed) .ToList(); if (!unknownTypes.Any()) { return(calls); } else { var children = Analyze(relevantNodes, interfaceImplementationsMap, callers.Concat(analyzed).Distinct().ToList(), unknownTypes); return(calls.Concat(children).ToList()); } }
// traces from the given source nodes all calls within the assembly graph private List <MethodCall> TraceCalles(IEnumerable <Node> relevantNodes, InterfaceImplementationsMap interfaceImplementationsMap, List <MethodDesc> targets, IEnumerable <Assembly> sources) { var targetTypes = targets .Select(m => m.myDeclaringType) .Distinct() .ToList(); return(Analyze(relevantNodes, interfaceImplementationsMap, targetTypes, sources.SelectMany(x => x.GetTypes()).ToList()) .Distinct() .ToList()); }
private GraphPresentation BuildCallTree(List <Assembly> sources, List <MethodDesc> targets, GraphPresentation assemblyGraphPresentation) { var relevantNodes = assemblyGraphPresentation.Graph.Nodes .Where(n => assemblyGraphPresentation.Picking.Pick(n)) .ToList(); var interfaceImplementationsMap = new InterfaceImplementationsMap(); interfaceImplementationsMap.Build(relevantNodes, targets.Select(t => t.myDeclaringType)); var calls = TraceCalles(relevantNodes, interfaceImplementationsMap, targets, sources); Console.WriteLine(); Console.WriteLine("NOT analyzed assemblies:"); foreach (var x in myMonoLoader.SkippedAssemblies) { Shell.Warn($" {x}"); } return(Shell.Profile("Generating call graph ...", () => { var builder = new RelaxedGraphBuilder(); var edges = calls .Select(call => (CreateMethodNode(call.From), CreateMethodNode(call.To))) // we assume that usages within same class are not relevant .Where(x => x.Item1.myDeclaringType != x.Item2.myDeclaringType) .ToList(); foreach (var edge in edges) { builder.TryAddEdge(edge.Item1.myId, edge.Item2.myId); } var nodes = edges .SelectMany(e => new[] { e.Item1, e.Item2 }) .Distinct(new MethodNodeComparer()) .ToList(); var clusters = nodes .GroupBy(n => n.myDeclaringType) .Select(x => (R.TypeFullName(x.Key), x.Key.Name, x.Select(n => n.myId).ToList())) .ToList(); foreach (var cluster in clusters) { builder.TryAddCluster(cluster.Item1, cluster.Item3); } builder.Freeze(); var presentation = new GraphPresentation(); presentation.Graph = builder.Graph; // add captions for readability var captions = presentation.GetModule <ICaptionModule>(); foreach (var n in nodes) { captions.Add(new Caption(n.myId, n.myCaption)); } foreach (var cluster in clusters) { captions.Add(new Caption(cluster.Item1, cluster.Item2)); } return presentation; }));