1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Benoth\StaticReflection\Parser; |
4
|
|
|
|
5
|
|
|
use Benoth\StaticReflection\Reflection\Reflection; |
6
|
|
|
use Benoth\StaticReflection\Reflection\ReflectionFunctionAbstract; |
7
|
|
|
use Benoth\StaticReflection\ReflectionsIndex; |
8
|
|
|
use PhpParser\Error as PhpParserException; |
9
|
|
|
use PhpParser\NodeTraverserInterface; |
10
|
|
|
use PhpParser\Parser as ParserInterface; |
11
|
|
|
|
12
|
|
|
class ParsingContext |
13
|
|
|
{ |
14
|
|
|
protected $parser; |
15
|
|
|
protected $traverser; |
16
|
|
|
protected $index; |
17
|
|
|
|
18
|
|
|
protected $file; |
19
|
|
|
protected $errors = []; |
20
|
|
|
|
21
|
|
|
protected $namespace; |
22
|
|
|
protected $aliases = []; |
23
|
|
|
protected $reflection; |
24
|
|
|
protected $functionLike; |
25
|
|
|
|
26
|
1128 |
|
public function __construct(ParserInterface $parser, NodeTraverserInterface $traverser, ReflectionsIndex $index) |
27
|
|
|
{ |
28
|
1128 |
|
ini_set('xdebug.max_nesting_level', 10000); |
29
|
|
|
|
30
|
1128 |
|
$this->parser = $parser; |
31
|
1128 |
|
$this->traverser = $traverser; |
32
|
1128 |
|
$this->index = $index; |
33
|
1128 |
|
} |
34
|
|
|
|
35
|
1128 |
|
public function parseFile($file) |
36
|
|
|
{ |
37
|
1128 |
|
$this->file = $file; |
38
|
1128 |
|
$this->errors = []; |
39
|
|
|
|
40
|
|
|
try { |
41
|
1128 |
|
$this->traverser->traverse($this->parser->parse($this->getFileContent())); |
|
|
|
|
42
|
1128 |
|
} catch (PhpParserException $e) { |
43
|
27 |
|
$this->addError($this->getFilePath(), 0, $e->getMessage()); |
44
|
|
|
} |
45
|
|
|
|
46
|
1128 |
|
$this->file = null; |
47
|
|
|
|
48
|
1128 |
|
return $this; |
49
|
|
|
} |
50
|
|
|
|
51
|
1128 |
|
public function getFilePath() |
52
|
|
|
{ |
53
|
1128 |
|
return $this->file; |
54
|
|
|
} |
55
|
|
|
|
56
|
1128 |
|
public function getFileContent() |
57
|
|
|
{ |
58
|
1128 |
|
if (!file_exists($this->getFilePath())) { |
59
|
27 |
|
throw new PhpParserException('File '.$this->getFilePath().' does not exist'); |
60
|
|
|
} |
61
|
|
|
|
62
|
1101 |
|
return file_get_contents($this->getFilePath()); |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* @param string $name |
67
|
|
|
*/ |
68
|
258 |
|
public function addAlias($alias, $name) |
69
|
|
|
{ |
70
|
258 |
|
$this->aliases[$alias] = $name; |
71
|
258 |
|
} |
72
|
|
|
|
73
|
1101 |
|
public function getAliases() |
74
|
|
|
{ |
75
|
1101 |
|
return $this->aliases; |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* @param string $namespace |
80
|
|
|
*/ |
81
|
1047 |
|
public function enterNamespace($namespace) |
82
|
|
|
{ |
83
|
1047 |
|
$this->namespace = $namespace; |
84
|
1047 |
|
$this->aliases = array(); |
85
|
|
|
|
86
|
1047 |
|
return $this; |
87
|
|
|
} |
88
|
|
|
|
89
|
1047 |
|
public function leaveNamespace() |
90
|
|
|
{ |
91
|
1047 |
|
$this->namespace = null; |
92
|
1047 |
|
$this->aliases = array(); |
93
|
|
|
|
94
|
1047 |
|
return $this; |
95
|
|
|
} |
96
|
|
|
|
97
|
6 |
|
public function getNamespace() |
98
|
|
|
{ |
99
|
6 |
|
return $this->namespace; |
100
|
|
|
} |
101
|
|
|
|
102
|
1101 |
|
public function enterReflection(Reflection $reflection) |
103
|
|
|
{ |
104
|
1101 |
|
$this->reflection = $reflection; |
105
|
1101 |
|
} |
106
|
|
|
|
107
|
1104 |
|
public function leaveReflection() |
108
|
|
|
{ |
109
|
1104 |
|
if ($this->reflection === null) { |
110
|
6 |
|
return; |
111
|
|
|
} |
112
|
|
|
|
113
|
1101 |
|
$this->index->addReflection($this->reflection); |
114
|
|
|
|
115
|
1101 |
|
$this->reflection = null; |
116
|
1101 |
|
} |
117
|
|
|
|
118
|
1101 |
|
public function enterFunctionLike(ReflectionFunctionAbstract $reflection) |
119
|
|
|
{ |
120
|
1101 |
|
$this->functionLike = $reflection; |
121
|
1101 |
|
} |
122
|
|
|
|
123
|
1104 |
|
public function getFunctionLike() |
124
|
|
|
{ |
125
|
1104 |
|
return $this->functionLike; |
126
|
|
|
} |
127
|
|
|
|
128
|
1104 |
|
public function leaveFunctionLike() |
129
|
|
|
{ |
130
|
1104 |
|
$this->functionLike = null; |
131
|
1104 |
|
} |
132
|
|
|
|
133
|
1104 |
|
public function getReflection() |
134
|
|
|
{ |
135
|
1104 |
|
return $this->reflection; |
136
|
|
|
} |
137
|
|
|
|
138
|
6 |
|
public function addErrors($name, $line, array $errors) |
139
|
|
|
{ |
140
|
6 |
|
foreach ($errors as $error) { |
141
|
6 |
|
$this->addError($name, $line, $error); |
142
|
6 |
|
} |
143
|
6 |
|
} |
144
|
|
|
|
145
|
33 |
|
public function addError($name, $line, $error) |
146
|
|
|
{ |
147
|
33 |
|
$this->errors[] = sprintf('%s on "%s" in %s:%d', $error, $name, $this->file, $line); |
148
|
33 |
|
} |
149
|
|
|
|
150
|
18 |
|
public function getErrors() |
151
|
|
|
{ |
152
|
18 |
|
return $this->errors; |
153
|
|
|
} |
154
|
|
|
} |
155
|
|
|
|
This check looks at variables that are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.