private void getReferencedFilesRecursive(DirectedTypeNode node, HashSet <string> result, HashSet <DirectedTypeNode> seenTypes = null, int level = 0)
        {
            // A '.' is prepended since the logger trims lines.
            logger.Add($"{(level > 0 ? $".{new string(' ', level * 2 - 1)}| " : string.Empty)} {node}");

            seenTypes ??= new HashSet <DirectedTypeNode>();
            if (seenTypes.Contains(node))
            {
                return;
            }

            seenTypes.Add(node);

            // Add all the current type's locations to the resulting set.
            foreach (var location in node.Reference.Symbol.Locations)
            {
                var syntaxTree = location.SourceTree;
                if (syntaxTree != null)
                {
                    result.Add(syntaxTree.FilePath);
                }
            }

            // Follow through the process for all parents.
            foreach (var p in node.Parents)
            {
                getReferencedFilesRecursive(p, result, seenTypes, level + 1);
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Traverses <see cref="referenceMap"/> to build a directed graph of <see cref="DirectedTypeNode"/> joined by their parents.
        /// </summary>
        /// <returns>A dictionary containing the directed graph from each <see cref="TypeReference"/> in <see cref="referenceMap"/>.</returns>
        private Dictionary <TypeReference, DirectedTypeNode> getDirectedGraph()
        {
            // Given the reference map (from above):
            //
            // P -> { C1, C2 }
            // C1 -> { C3, C4 }
            // C2 -> { C5, C6 }
            // C3 -> { }
            // C4 -> { C6 }
            // C5 -> { C6 }
            // C6 -> { C2 }
            //
            // The respective directed graph is built by traversing upwards and finding all incoming references at each type, such that:
            //
            // P -> { }
            // C1 -> { P }
            // C2 -> { C6, P, C5, C4, C2, C1 }
            // C3 -> { C1, P }
            // C4 -> { C1, P }
            // C5 -> { C2, P }
            // C6 -> { C5, C4, C2, C1, C6, P }
            //
            // The directed graph may contain cycles where multiple paths lead to the same node (e.g. C2, C6).

            logger.Add("Retrieving reference graph...");

            var result = new Dictionary <TypeReference, DirectedTypeNode>();

            // Traverse through the reference map and assign parents to all children referenced types.
            foreach (var kvp in referenceMap)
            {
                var parentNode = getNode(kvp.Key);
                foreach (var typeRef in kvp.Value)
                {
                    getNode(typeRef).Parents.Add(parentNode);
                }
            }

            return(result);

            DirectedTypeNode getNode(TypeReference typeSymbol)
            {
                if (!result.TryGetValue(typeSymbol, out var existing))
                {
                    result[typeSymbol] = existing = new DirectedTypeNode(typeSymbol);
                }
                return(existing);
            }
        }
Exemplo n.º 3
0
        private bool computeExpansionFactors(DirectedTypeNode node, HashSet <DirectedTypeNode> seenTypes = null)
        {
            seenTypes ??= new HashSet <DirectedTypeNode>();
            if (seenTypes.Contains(node))
            {
                return(false);
            }

            seenTypes.Add(node);

            node.ExpansionFactor = (ulong)node.Parents.Count;

            foreach (var p in node.Parents)
            {
                if (computeExpansionFactors(p, seenTypes))
                {
                    node.ExpansionFactor += p.ExpansionFactor;
                }
            }

            return(true);
        }
Exemplo n.º 4
0
 private void getReferencedFilesRecursive(DirectedTypeNode node, HashSet <string> result, (double min, double max) exclusionRange, HashSet <DirectedTypeNode> seenTypes = null,