55namespace Smeghead \PhpVariableHardUsage \Parse ;
66
77use PhpParser \Node \Expr \Variable ;
8- use PhpParser \Node \Stmt ;
9- use PhpParser \Node \Stmt \ClassMethod ;
10- use PhpParser \Node \Stmt \Class_ ;
11- use PhpParser \Node \Stmt \Function_ ;
12- use PhpParser \NodeDumper ;
13- use PhpParser \NodeVisitor \FindingVisitor ;
8+ use PhpParser \Node \FunctionLike ;
9+ use PhpParser \NodeFinder ;
10+ use PhpParser \NodeTraverser ;
1411use PhpParser \Parser ;
1512use Smeghead \PhpVariableHardUsage \Parse \Exception \ParseFailedException ;
13+ use Smeghead \PhpVariableHardUsage \Parse \Visitor \FunctionLikeFindingVisitor ;
1614
1715final class VariableParser
1816{
1917 private Parser $ parser ;
2018
19+ private NodeFinder $ nodeFinder ;
20+
2121 public function __construct ()
2222 {
2323 $ this ->parser = (new \PhpParser \ParserFactory ())->createForNewestSupportedVersion ();
24+ $ this ->nodeFinder = new NodeFinder ();
2425 }
2526
26- /**
27- * @param list<Stmt> $stmt
28- * @return list<Function_>
29- */
30- private function getFunctions (array $ stmt ): array
27+ public function parse (string $ content ): ParseResult
3128 {
32- $ functionVisitor = new FindingVisitor (function ($ node ) {
33- return $ node instanceof Function_;
34- });
35- $ traverser = new \PhpParser \NodeTraverser ();
36- $ traverser ->addVisitor ($ functionVisitor );
37- $ traverser ->traverse ($ stmt );
29+ $ stmts = $ this ->parser ->parse ($ content );
30+ if ($ stmts === null ) {
31+ throw new ParseFailedException ();
32+ }
3833
39- return $ functionVisitor ->getFoundNodes (); // @phpstan-ignore-line
40- }
34+ $ traverser = new NodeTraverser ();
35+ $ visitor = new FunctionLikeFindingVisitor (fn ($ node ) => $ node instanceof FunctionLike);
36+ $ traverser ->addVisitor ($ visitor );
37+ $ traverser ->traverse ($ stmts );
38+ $ functionLikes = $ visitor ->getFoundNodes ();
4139
42- /**
43- * @param Function_|ClassMethod $function
44- * @return list<Variable>
45- */
46- private function getVariables (Function_ |ClassMethod $ function ): array
47- {
48- $ variableVisitor = new FindingVisitor (function ($ node ) {
49- return $ node instanceof Variable;
50- });
51- $ traverser = new \PhpParser \NodeTraverser ();
52- $ traverser ->addVisitor ($ variableVisitor );
53- $ traverser ->traverse ([$ function ]);
40+ $ functions = $ this ->collectParseResultPerFunctionLike ($ functionLikes );
5441
55- return $ variableVisitor -> getFoundNodes (); // @phpstan-ignore-line
42+ return new ParseResult ( $ functions );
5643 }
5744
5845 /**
59- * @param list<Stmt > $stmts
46+ * @param list<FunctionLike > $functionLikes
6047 * @return list<Func>
6148 */
62- private function parseFunctions (array $ stmts ): array
49+ private function collectParseResultPerFunctionLike (array $ functionLikes ): array
6350 {
64- $ foundFunctions = $ this ->getFunctions ($ stmts );
65-
66- $ functions = [];
67- foreach ($ foundFunctions as $ foundFunction ) {
68- $ variables = $ this ->getVariables ($ foundFunction );
69- $ func = new Func ($ foundFunction ->name ->name );
51+ return array_map (function (FunctionLike $ function ) {
52+ $ className = $ function ->getAttribute ('className ' ); // Get the class name set in FunctionLikeFindingVisitor
53+ $ functionName = $ function ->name ->name ?? $ function ->getType () . '@ ' . $ function ->getStartLine ();
54+ $ functionIdentifier = sprintf (
55+ '%s%s ' ,
56+ isset ($ className ) ? $ className . ':: ' : '' ,
57+ $ functionName
58+ );
59+
60+ $ func = new Func ($ functionIdentifier );
61+
62+ $ variables = $ this ->nodeFinder ->findInstanceOf ($ function , Variable::class);
7063 foreach ($ variables as $ variable ) {
7164 $ func ->addVariable (new VarReference ($ variable ->name , $ variable ->getLine ())); // @phpstan-ignore-line
7265 }
73- $ functions [] = $ func ;
74- }
75- return $ functions ;
76- }
77-
78- /**
79- * @param list<Stmt> $stmt
80- * @return list<Class_>
81- */
82- private function getClasses (array $ stmt ): array
83- {
84- $ classVisitor = new FindingVisitor (function ($ node ) {
85- return $ node instanceof \PhpParser \Node \Stmt \Class_;
86- });
87- $ traverser = new \PhpParser \NodeTraverser ();
88- $ traverser ->addVisitor ($ classVisitor );
89- $ traverser ->traverse ($ stmt );
90-
91- return $ classVisitor ->getFoundNodes (); // @phpstan-ignore-line
92- }
93-
94- /**
95- * @param list<Stmt> $stmts
96- * @return list<Func>
97- */
98- private function parseClasses (array $ stmts ): array
99- {
100- $ foundClasses = $ this ->getClasses ($ stmts );
101-
102- $ methods = [];
103- foreach ($ foundClasses as $ foundClass ) {
104- foreach ($ foundClass ->getMethods () as $ method ) {
105- $ variables = $ this ->getVariables ($ method );
106- $ func = new Func (sprintf ('%s::%s ' , $ foundClass ->name , $ method ->name ->name ));
107- foreach ($ variables as $ variable ) {
108- $ func ->addVariable (new VarReference ($ variable ->name , $ variable ->getLine ())); // @phpstan-ignore-line
109- }
110- $ methods [] = $ func ;
111- }
112- }
113- return $ methods ;
114- }
115-
116- public function parse (string $ content ): ParseResult
117- {
118- $ stmts = $ this ->parser ->parse ($ content );
119- if ($ stmts === null ) {
120- throw new ParseFailedException ();
121- }
122- $ dumper = new NodeDumper ();
123- // echo $dumper->dump($stmts) . PHP_EOL;
124-
125- $ functions = $ this ->parseFunctions ($ stmts ) + $ this ->parseClasses ($ stmts );
126-
127- return new ParseResult ($ functions );
66+ return $ func ;
67+ }, $ functionLikes );
12868 }
12969}
0 commit comments