public static SymbolStat SearchCFG(PhpCompilation compilation, ControlFlowGraph cfg, int position)
        {
            var visitor = new SourceSymbolSearcher(position)
            {
                DeclaringCompilation = compilation,
            };

            visitor.VisitCFG(cfg);
            return(visitor._result);
        }
        public static SourceSymbolSearcher.SymbolStat FindDefinition(PhpCompilation compilation, string filepath, int line, int character)
        {
            var tree = compilation.SyntaxTrees.FirstOrDefault(t => t.FilePath == filepath);

            if (tree == null)
            {
                return(null);
            }

            // Get the position in the file
            int position = tree.GetOffset(new LinePosition(line, character));

            if (position == -1)
            {
                return(null);
            }

            // Find the bound node corresponding to the text position
            SourceSymbolSearcher.SymbolStat searchResult = null;
            foreach (var routine in compilation.GetUserDeclaredRoutinesInFile(tree))
            {
                // Consider only routines containing the position being searched (<Main> has span [0..0])
                if (routine.IsGlobalScope || routine.GetSpan().Contains(position))
                {
                    // Search parameters at first
                    searchResult = SourceSymbolSearcher.SearchParameters(routine, position);
                    if (searchResult != null)
                    {
                        break;
                    }

                    // Search the routine body
                    searchResult = SourceSymbolSearcher.SearchCFG(compilation, routine.ControlFlowGraph, position);
                    if (searchResult != null)
                    {
                        break;
                    }
                }
            }

            return(searchResult);
        }