public static string GetNodeTreeHashString(VB6SubTree nodeTree)
        {
            if (nodeTree == null)
            {
                throw new ArgumentNullException(nameof(nodeTree));
            }

            var typeNames = new List <string>();
            var count     = 0;

            foreach (var node in nodeTree.GetAllNodes())
            {
                typeNames.Add(VbToCsharpPattern.LookupNodeType(node));
                count++;
                if (count > 20)
                {
                    break;
                }
            }
            return(String.Join("/", typeNames));
        }
        public void GetPatterns(VB6NodeTree nodeTree)
        {
            if (nodeTree == null)
            {
                throw new ArgumentNullException(nameof(nodeTree));
            }

            // Iterate over all nodes and add them to node hash based on their concatenated type strings
            foreach (var node in nodeTree.GetAllNodes())
            {
                var subtree = new VB6SubTree(nodeTree, node);

                //var nodeTreeHashString = GetNodeTreeHashString(subtree);
                var nodeHash = GetNodeHash(node);

                if (!nodeHashDict.ContainsKey(nodeHash))
                {
                    nodeHashDict[nodeHash] = new Dictionary <string, List <VB6SubTree> >();
                }
                var tokens = String.Join(" ", GetTokens(node));
                if (!nodeHashDict[nodeHash].ContainsKey(tokens))
                {
                    nodeHashDict[nodeHash][tokens] = new List <VB6SubTree>();
                }
                nodeHashDict[nodeHash][tokens].Add(subtree);
            }

            foreach (var key in nodeHashDict.Keys)
            {
                foreach (var key2 in nodeHashDict[key].Keys)
                {
                    var s = new List <string>();
                    foreach (var subtree in nodeHashDict[key][key2])
                    {
                        var node   = subtree.GetRoot();
                        var tokens = String.Join(" ", GetTokens(node));
                        s.Add(tokens);
                    }
                    var s2 = String.Join(", ", s);
                    DebugClass.LogError("NodeTreeHashString: " + key + " " + key2 + ": " + nodeHashDict[key][key2].Count + ": " + s2);
                }
            }

            // TODO: Is it possible to auto-generate this dictionary?
            // No stress, it's small, but would be nice for other languages.
            var replaceable = new Dictionary <string, bool>();

            replaceable["AmbiguousIdentifierContext"] = true;
            replaceable["CertainIdentifierContext"]   = true;
            replaceable["LiteralContext"]             = true;
            replaceable["FieldLengthContext"]         = true;

            // Iterate over all nodes and replace each token/text in pattern with pattern letter,
            // if there are two or more variations of this token under this node type name
            const string letters = "ABCDEFGHIJKLMNOPQRSTUVXYZ";

            foreach (var node in nodeTree.GetAllNodes())
            {
                var subtree     = new VB6SubTree(nodeTree, node);
                int letterIndex = 0;
                var text        = node.getText();
                var pattern     = text;

                foreach (var child in subtree.GetAllNodes())
                {
                    if (replaceable.ContainsKey(VbToCsharpPattern.LookupNodeType(child)))
                    {
                        //DebugClass.LogError("REPLACING: " + VbToCsharpPattern.LookupNodeType(child));
                        var tokens = GetTokens(child);
                        foreach (var token in tokens)
                        {
                            if (letterIndex < letters.Length)
                            {
                                var oldPattern = pattern;
                                pattern = pattern.Replace(token, letters[letterIndex].ToString(System.Globalization.CultureInfo.InvariantCulture));
                                if (pattern != oldPattern)
                                {
                                    letterIndex++;
                                }
                                //DebugClass.LogError("REPLACING: " + token);
                            }

                            if (letterIndex >= letters.Length)
                            {
                                break;
                            }
                        }
                        if (letterIndex >= letters.Length)
                        {
                            break;
                        }
                    }
                }
                if (pattern.Length >= 100)
                {
                    pattern = "PATTERN TOO LONG";
                }
                generatedPatterns[node] = pattern;
            }
        }