private void TakeSiblingsOf(TypeRelationshipDocument document, HashSet <TypeDescriptor> visitedTypes, params TypeDescriptor[] roots)
        {
            if (!roots.Any())
            {
                return;
            }

            var typesToFollow = new HashSet <TypeDescriptor>();

            foreach (var root in roots)
            {
                visitedTypes.Add(root);

                var node = myBuilder.Graph.FindNode(root.Id);

                foreach (var edge in node.In)
                {
                    var source = myIdToTypeMap[edge.Source.Id];
                    document.AddEdge(source, root, myEdgeTypes[edge.Id]);
                    typesToFollow.Add(source);
                }

                // TODO: down only - otherwise we need a "MaxDepth"
                //foreach( var edge in node.Out )
                //{
                //    var target = myIdToTypeMap[ edge.Target.Id ];
                //    document.AddEdge( root, target );
                //    typesToFollow.Add( target );
                //}
            }

            typesToFollow.ExceptWith(visitedTypes);

            TakeSiblingsOf(document, visitedTypes, typesToFollow.ToArray());
        }
        private void ProcessAssembly(string assemblyName, TypeRelationshipDocument document, string assemblyFile)
        {
            try
            {
                var assembly = Assembly.LoadFrom(assemblyFile);
                if (assembly.GetName().ToString() == assemblyName ||
                    assembly.GetReferencedAssemblies().Any(r => r.ToString() == assemblyName))
                {
                    foreach (var type in assembly.GetTypes())
                    {
                        ProcessType(type);
                    }
                }
            }
            catch (ReflectionTypeLoadException ex)
            {
                var sb = new StringBuilder();
                sb.AppendLine("Failed to load assembly");

                foreach (var loaderEx in ex.LoaderExceptions)
                {
                    sb.Append("  LoaderException (");
                    sb.Append(loaderEx.GetType().Name);
                    sb.Append(") ");
                    sb.AppendLine(loaderEx.Message);
                }

                document.AddFailedItem(new FailedItem(assemblyFile, sb.ToString().Trim()));
            }
            catch (Exception ex)
            {
                var sb = new StringBuilder();
                sb.Append("Failed to load assembly: ");
                sb.Append(ex.Message);

                document.AddFailedItem(new FailedItem(assemblyFile, sb.ToString()));
            }
        }
        public TypeRelationshipDocument Execute(string assemblyLocation, TypeDescriptor type, CancellationToken cancellationToken)
        {
            var assemblyHome = Path.GetDirectoryName(assemblyLocation);
            var assemblyName = AssemblyName.GetAssemblyName(assemblyLocation).ToString();

            Console.Write(".");

            var assemblies = Directory.EnumerateFiles(assemblyHome, "*.dll")
                             .Concat(Directory.EnumerateFiles(assemblyHome, "*.exe"))
                             .AsParallel()
                             .Where(file => File.Exists(file))
                             .Where(file => AssemblyUtils.IsManagedAssembly(file))
                             .ToArray();

            Console.Write(".");

            cancellationToken.ThrowIfCancellationRequested();

            var document = new TypeRelationshipDocument();


            foreach (var assemblyFile in assemblies)
            {
                ProcessAssembly(assemblyName, document, assemblyFile);

                Console.Write(".");

                cancellationToken.ThrowIfCancellationRequested();
            }

            var visitedTypes = new HashSet <TypeDescriptor>();

            TakeSiblingsOf(document, visitedTypes, myIdToTypeMap[type.Id]);

            return(document);
        }