Chris@17
|
1 <?php
|
Chris@17
|
2 /**
|
Chris@17
|
3 * A local file represents a chunk of text has a file system location.
|
Chris@17
|
4 *
|
Chris@17
|
5 * @author Greg Sherwood <gsherwood@squiz.net>
|
Chris@17
|
6 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
|
Chris@17
|
7 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
Chris@17
|
8 */
|
Chris@17
|
9
|
Chris@17
|
10 namespace PHP_CodeSniffer\Files;
|
Chris@17
|
11
|
Chris@17
|
12 use PHP_CodeSniffer\Ruleset;
|
Chris@17
|
13 use PHP_CodeSniffer\Config;
|
Chris@17
|
14 use PHP_CodeSniffer\Util\Cache;
|
Chris@17
|
15
|
Chris@17
|
16 class LocalFile extends File
|
Chris@17
|
17 {
|
Chris@17
|
18
|
Chris@17
|
19
|
Chris@17
|
20 /**
|
Chris@17
|
21 * Creates a LocalFile object and sets the content.
|
Chris@17
|
22 *
|
Chris@17
|
23 * @param string $path The absolute path to the file.
|
Chris@17
|
24 * @param \PHP_CodeSniffer\Ruleset $ruleset The ruleset used for the run.
|
Chris@17
|
25 * @param \PHP_CodeSniffer\Config $config The config data for the run.
|
Chris@17
|
26 *
|
Chris@17
|
27 * @return void
|
Chris@17
|
28 */
|
Chris@17
|
29 public function __construct($path, Ruleset $ruleset, Config $config)
|
Chris@17
|
30 {
|
Chris@17
|
31 $this->path = trim($path);
|
Chris@17
|
32 if (is_readable($this->path) === false) {
|
Chris@17
|
33 parent::__construct($this->path, $ruleset, $config);
|
Chris@17
|
34 $error = 'Error opening file; file no longer exists or you do not have access to read the file';
|
Chris@17
|
35 $this->addMessage(true, $error, 1, 1, 'Internal.LocalFile', [], 5, false);
|
Chris@17
|
36 $this->ignored = true;
|
Chris@17
|
37 return;
|
Chris@17
|
38 }
|
Chris@17
|
39
|
Chris@17
|
40 // Before we go and spend time tokenizing this file, just check
|
Chris@17
|
41 // to see if there is a tag up top to indicate that the whole
|
Chris@17
|
42 // file should be ignored. It must be on one of the first two lines.
|
Chris@17
|
43 if ($config->annotations === true) {
|
Chris@17
|
44 $handle = fopen($this->path, 'r');
|
Chris@17
|
45 if ($handle !== false) {
|
Chris@17
|
46 $firstContent = fgets($handle);
|
Chris@17
|
47 $firstContent .= fgets($handle);
|
Chris@17
|
48 fclose($handle);
|
Chris@17
|
49
|
Chris@17
|
50 if (strpos($firstContent, '@codingStandardsIgnoreFile') !== false
|
Chris@17
|
51 || stripos($firstContent, 'phpcs:ignorefile') !== false
|
Chris@17
|
52 ) {
|
Chris@17
|
53 // We are ignoring the whole file.
|
Chris@17
|
54 $this->ignored = true;
|
Chris@17
|
55 return;
|
Chris@17
|
56 }
|
Chris@17
|
57 }
|
Chris@17
|
58 }
|
Chris@17
|
59
|
Chris@17
|
60 $this->reloadContent();
|
Chris@17
|
61
|
Chris@18
|
62 parent::__construct($this->path, $ruleset, $config);
|
Chris@17
|
63
|
Chris@17
|
64 }//end __construct()
|
Chris@17
|
65
|
Chris@17
|
66
|
Chris@17
|
67 /**
|
Chris@17
|
68 * Loads the latest version of the file's content from the file system.
|
Chris@17
|
69 *
|
Chris@17
|
70 * @return void
|
Chris@17
|
71 */
|
Chris@17
|
72 public function reloadContent()
|
Chris@17
|
73 {
|
Chris@17
|
74 $this->setContent(file_get_contents($this->path));
|
Chris@17
|
75
|
Chris@17
|
76 }//end reloadContent()
|
Chris@17
|
77
|
Chris@17
|
78
|
Chris@17
|
79 /**
|
Chris@17
|
80 * Processes the file.
|
Chris@17
|
81 *
|
Chris@17
|
82 * @return void
|
Chris@17
|
83 */
|
Chris@17
|
84 public function process()
|
Chris@17
|
85 {
|
Chris@17
|
86 if ($this->ignored === true) {
|
Chris@17
|
87 return;
|
Chris@17
|
88 }
|
Chris@17
|
89
|
Chris@17
|
90 if ($this->configCache['cache'] === false) {
|
Chris@18
|
91 parent::process();
|
Chris@18
|
92 return;
|
Chris@17
|
93 }
|
Chris@17
|
94
|
Chris@17
|
95 $hash = md5_file($this->path);
|
Chris@17
|
96 $cache = Cache::get($this->path);
|
Chris@17
|
97 if ($cache !== false && $cache['hash'] === $hash) {
|
Chris@17
|
98 // We can't filter metrics, so just load all of them.
|
Chris@17
|
99 $this->metrics = $cache['metrics'];
|
Chris@17
|
100
|
Chris@17
|
101 if ($this->configCache['recordErrors'] === true) {
|
Chris@17
|
102 // Replay the cached errors and warnings to filter out the ones
|
Chris@17
|
103 // we don't need for this specific run.
|
Chris@17
|
104 $this->configCache['cache'] = false;
|
Chris@17
|
105 $this->replayErrors($cache['errors'], $cache['warnings']);
|
Chris@17
|
106 $this->configCache['cache'] = true;
|
Chris@17
|
107 } else {
|
Chris@17
|
108 $this->errorCount = $cache['errorCount'];
|
Chris@17
|
109 $this->warningCount = $cache['warningCount'];
|
Chris@17
|
110 $this->fixableCount = $cache['fixableCount'];
|
Chris@17
|
111 }
|
Chris@17
|
112
|
Chris@17
|
113 if (PHP_CODESNIFFER_VERBOSITY > 0
|
Chris@17
|
114 || (PHP_CODESNIFFER_CBF === true && empty($this->config->files) === false)
|
Chris@17
|
115 ) {
|
Chris@17
|
116 echo "[loaded from cache]... ";
|
Chris@17
|
117 }
|
Chris@17
|
118
|
Chris@17
|
119 $this->numTokens = $cache['numTokens'];
|
Chris@17
|
120 $this->fromCache = true;
|
Chris@17
|
121 return;
|
Chris@17
|
122 }//end if
|
Chris@17
|
123
|
Chris@17
|
124 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@17
|
125 echo PHP_EOL;
|
Chris@17
|
126 }
|
Chris@17
|
127
|
Chris@17
|
128 parent::process();
|
Chris@17
|
129
|
Chris@17
|
130 $cache = [
|
Chris@17
|
131 'hash' => $hash,
|
Chris@17
|
132 'errors' => $this->errors,
|
Chris@17
|
133 'warnings' => $this->warnings,
|
Chris@17
|
134 'metrics' => $this->metrics,
|
Chris@17
|
135 'errorCount' => $this->errorCount,
|
Chris@17
|
136 'warningCount' => $this->warningCount,
|
Chris@17
|
137 'fixableCount' => $this->fixableCount,
|
Chris@17
|
138 'numTokens' => $this->numTokens,
|
Chris@17
|
139 ];
|
Chris@17
|
140
|
Chris@17
|
141 Cache::set($this->path, $cache);
|
Chris@17
|
142
|
Chris@17
|
143 // During caching, we don't filter out errors in any way, so
|
Chris@17
|
144 // we need to do that manually now by replaying them.
|
Chris@17
|
145 if ($this->configCache['recordErrors'] === true) {
|
Chris@17
|
146 $this->configCache['cache'] = false;
|
Chris@17
|
147 $this->replayErrors($this->errors, $this->warnings);
|
Chris@17
|
148 $this->configCache['cache'] = true;
|
Chris@17
|
149 }
|
Chris@17
|
150
|
Chris@17
|
151 }//end process()
|
Chris@17
|
152
|
Chris@17
|
153
|
Chris@17
|
154 /**
|
Chris@17
|
155 * Clears and replays error and warnings for the file.
|
Chris@17
|
156 *
|
Chris@17
|
157 * Replaying errors and warnings allows for filtering rules to be changed
|
Chris@17
|
158 * and then errors and warnings to be reapplied with the new rules. This is
|
Chris@17
|
159 * particularly useful while caching.
|
Chris@17
|
160 *
|
Chris@17
|
161 * @param array $errors The list of errors to replay.
|
Chris@17
|
162 * @param array $warnings The list of warnings to replay.
|
Chris@17
|
163 *
|
Chris@17
|
164 * @return void
|
Chris@17
|
165 */
|
Chris@17
|
166 private function replayErrors($errors, $warnings)
|
Chris@17
|
167 {
|
Chris@17
|
168 $this->errors = [];
|
Chris@17
|
169 $this->warnings = [];
|
Chris@17
|
170 $this->errorCount = 0;
|
Chris@17
|
171 $this->warningCount = 0;
|
Chris@17
|
172 $this->fixableCount = 0;
|
Chris@17
|
173
|
Chris@17
|
174 foreach ($errors as $line => $lineErrors) {
|
Chris@17
|
175 foreach ($lineErrors as $column => $colErrors) {
|
Chris@17
|
176 foreach ($colErrors as $error) {
|
Chris@17
|
177 $this->activeListener = $error['listener'];
|
Chris@17
|
178 $this->addMessage(
|
Chris@17
|
179 true,
|
Chris@17
|
180 $error['message'],
|
Chris@17
|
181 $line,
|
Chris@17
|
182 $column,
|
Chris@17
|
183 $error['source'],
|
Chris@17
|
184 [],
|
Chris@17
|
185 $error['severity'],
|
Chris@17
|
186 $error['fixable']
|
Chris@17
|
187 );
|
Chris@17
|
188 }
|
Chris@17
|
189 }
|
Chris@17
|
190 }
|
Chris@17
|
191
|
Chris@17
|
192 foreach ($warnings as $line => $lineErrors) {
|
Chris@17
|
193 foreach ($lineErrors as $column => $colErrors) {
|
Chris@17
|
194 foreach ($colErrors as $error) {
|
Chris@17
|
195 $this->activeListener = $error['listener'];
|
Chris@17
|
196 $this->addMessage(
|
Chris@17
|
197 false,
|
Chris@17
|
198 $error['message'],
|
Chris@17
|
199 $line,
|
Chris@17
|
200 $column,
|
Chris@17
|
201 $error['source'],
|
Chris@17
|
202 [],
|
Chris@17
|
203 $error['severity'],
|
Chris@17
|
204 $error['fixable']
|
Chris@17
|
205 );
|
Chris@17
|
206 }
|
Chris@17
|
207 }
|
Chris@17
|
208 }
|
Chris@17
|
209
|
Chris@17
|
210 }//end replayErrors()
|
Chris@17
|
211
|
Chris@17
|
212
|
Chris@17
|
213 }//end class
|