Skip to content

Commit c72d43a

Browse files
authored
Extract FileAnalyserCallback (#4872)
1 parent 124af5f commit c72d43a

2 files changed

Lines changed: 340 additions & 172 deletions

File tree

src/Analyser/FileAnalyser.php

Lines changed: 22 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,13 @@
1313
use PHPStan\DependencyInjection\AutowiredParameter;
1414
use PHPStan\DependencyInjection\AutowiredService;
1515
use PHPStan\Node\FileNode;
16-
use PHPStan\Node\InClassNode;
17-
use PHPStan\Node\InTraitNode;
1816
use PHPStan\Parser\Parser;
1917
use PHPStan\Parser\ParserErrorsException;
2018
use PHPStan\Rules\Registry as RuleRegistry;
21-
use function array_keys;
2219
use function array_unique;
2320
use function array_values;
2421
use function count;
2522
use function error_reporting;
26-
use function get_class;
2723
use function hash;
2824
use function is_dir;
2925
use function is_file;
@@ -102,168 +98,36 @@ public function analyseFile(
10298
$this->collectErrors($analysedFiles);
10399
$parserNodes = $this->parser->parseFile($file);
104100
$processedFiles[] = $file;
105-
$linesToIgnore = $unmatchedLineIgnores = [$file => $this->getLinesToIgnoreFromTokens($parserNodes)];
106-
$ignoreErrorExtensions = $this->ignoreErrorExtensionProvider->getExtensions();
107-
$temporaryFileErrors = [];
108-
$nodeCallback = function (Node $node, $scope) use (&$fileErrors, &$fileCollectedData, &$fileDependencies, &$usedTraitFileDependencies, &$exportedNodes, $file, $ruleRegistry, $collectorRegistry, $outerNodeCallback, $analysedFiles, &$linesToIgnore, &$unmatchedLineIgnores, &$temporaryFileErrors, &$processedFiles, $parserNodes, $ignoreErrorExtensions): void {
109-
/** @var Scope&NodeCallbackInvoker $scope */
110-
if ($node instanceof Node\Stmt\Trait_) {
111-
foreach (array_keys($linesToIgnore[$file] ?? []) as $lineToIgnore) {
112-
if ($lineToIgnore < $node->getStartLine() || $lineToIgnore > $node->getEndLine()) {
113-
continue;
114-
}
115-
116-
unset($unmatchedLineIgnores[$file][$lineToIgnore]);
117-
}
118-
}
119-
if ($node instanceof InTraitNode) {
120-
$traitNode = $node->getOriginalNode();
121-
$fileDescription = $scope->getFileDescription();
122-
$linesToIgnore[$fileDescription] ??= [];
123-
$linesToIgnore[$fileDescription] += $this->getLinesToIgnoreFromTokens([$traitNode]);
124-
125-
$traitFileName = $node->getTraitReflection()->getFileName();
126-
if ($traitFileName !== null) {
127-
$processedFiles[] = $traitFileName;
128-
}
129-
}
130-
131-
if ($scope->isInTrait()) {
132-
$traitReflection = $scope->getTraitReflection();
133-
if ($traitReflection->getFileName() !== null) {
134-
$traitFilePath = $traitReflection->getFileName();
135-
$parserNodes = $this->parser->parseFile($traitFilePath);
136-
}
137-
}
138-
139-
if ($outerNodeCallback !== null) {
140-
$outerNodeCallback($node, $scope);
141-
}
142-
$uniquedAnalysedCodeExceptionMessages = [];
143-
$nodeType = get_class($node);
144-
foreach ($ruleRegistry->getRules($nodeType) as $rule) {
145-
try {
146-
$ruleErrors = $rule->processNode($node, $scope);
147-
} catch (AnalysedCodeException $e) {
148-
if (isset($uniquedAnalysedCodeExceptionMessages[$e->getMessage()])) {
149-
continue;
150-
}
151-
152-
$uniquedAnalysedCodeExceptionMessages[$e->getMessage()] = true;
153-
$fileErrors[] = (new Error($e->getMessage(), $file, $node->getStartLine(), $e, tip: $e->getTip()))
154-
->withIdentifier('phpstan.internal')
155-
->withMetadata([
156-
InternalError::STACK_TRACE_METADATA_KEY => InternalError::prepareTrace($e),
157-
InternalError::STACK_TRACE_AS_STRING_METADATA_KEY => $e->getTraceAsString(),
158-
]);
159-
continue;
160-
} catch (IdentifierNotFound $e) {
161-
$fileErrors[] = (new Error(sprintf('Reflection error: %s not found.', $e->getIdentifier()->getName()), $file, $node->getStartLine(), $e, tip: 'Learn more at https://phpstan.org/user-guide/discovering-symbols'))
162-
->withIdentifier('phpstan.reflection')
163-
->withMetadata([
164-
InternalError::STACK_TRACE_METADATA_KEY => InternalError::prepareTrace($e),
165-
InternalError::STACK_TRACE_AS_STRING_METADATA_KEY => $e->getTraceAsString(),
166-
]);
167-
continue;
168-
} catch (UnableToCompileNode | CircularReference $e) {
169-
$fileErrors[] = (new Error(sprintf('Reflection error: %s', $e->getMessage()), $file, $node->getStartLine(), $e))
170-
->withIdentifier('phpstan.reflection')
171-
->withMetadata([
172-
InternalError::STACK_TRACE_METADATA_KEY => InternalError::prepareTrace($e),
173-
InternalError::STACK_TRACE_AS_STRING_METADATA_KEY => $e->getTraceAsString(),
174-
]);
175-
continue;
176-
}
177-
178-
foreach ($ruleErrors as $ruleError) {
179-
$error = $this->ruleErrorTransformer->transform($ruleError, $scope, $parserNodes, $node);
180-
181-
if ($error->canBeIgnored()) {
182-
foreach ($ignoreErrorExtensions as $ignoreErrorExtension) {
183-
if ($ignoreErrorExtension->shouldIgnore($error, $node, $scope)) {
184-
continue 2;
185-
}
186-
}
187-
}
188-
189-
$temporaryFileErrors[] = $error;
190-
}
191-
}
192-
193-
foreach ($collectorRegistry->getCollectors($nodeType) as $collector) {
194-
try {
195-
$collectedData = $collector->processNode($node, $scope);
196-
} catch (AnalysedCodeException $e) {
197-
if (isset($uniquedAnalysedCodeExceptionMessages[$e->getMessage()])) {
198-
continue;
199-
}
200-
201-
$uniquedAnalysedCodeExceptionMessages[$e->getMessage()] = true;
202-
$fileErrors[] = (new Error($e->getMessage(), $file, $node->getStartLine(), $e, tip: $e->getTip()))
203-
->withIdentifier('phpstan.internal')
204-
->withMetadata([
205-
InternalError::STACK_TRACE_METADATA_KEY => InternalError::prepareTrace($e),
206-
InternalError::STACK_TRACE_AS_STRING_METADATA_KEY => $e->getTraceAsString(),
207-
]);
208-
continue;
209-
} catch (IdentifierNotFound $e) {
210-
$fileErrors[] = (new Error(sprintf('Reflection error: %s not found.', $e->getIdentifier()->getName()), $file, $node->getStartLine(), $e, tip: 'Learn more at https://phpstan.org/user-guide/discovering-symbols'))
211-
->withIdentifier('phpstan.reflection')
212-
->withMetadata([
213-
InternalError::STACK_TRACE_METADATA_KEY => InternalError::prepareTrace($e),
214-
InternalError::STACK_TRACE_AS_STRING_METADATA_KEY => $e->getTraceAsString(),
215-
]);
216-
continue;
217-
} catch (UnableToCompileNode | CircularReference $e) {
218-
$fileErrors[] = (new Error(sprintf('Reflection error: %s', $e->getMessage()), $file, $node->getStartLine(), $e))
219-
->withIdentifier('phpstan.reflection')
220-
->withMetadata([
221-
InternalError::STACK_TRACE_METADATA_KEY => InternalError::prepareTrace($e),
222-
InternalError::STACK_TRACE_AS_STRING_METADATA_KEY => $e->getTraceAsString(),
223-
]);
224-
continue;
225-
}
226-
227-
if ($collectedData === null) {
228-
continue;
229-
}
230-
231-
$fileCollectedData[$scope->getFile()][get_class($collector)][] = $collectedData;
232-
}
233-
234-
try {
235-
$dependencies = $this->dependencyResolver->resolveDependencies($node, $scope);
236-
foreach ($dependencies->getFileDependencies($scope->getFile(), $analysedFiles) as $dependentFile) {
237-
$fileDependencies[] = $dependentFile;
238-
}
239-
if ($dependencies->getExportedNode() !== null) {
240-
$exportedNodes[] = $dependencies->getExportedNode();
241-
}
242-
} catch (AnalysedCodeException) {
243-
// pass
244-
} catch (IdentifierNotFound) {
245-
// pass
246-
} catch (UnableToCompileNode) {
247-
// pass
248-
}
249-
250-
if (!$node instanceof InClassNode) {
251-
return;
252-
}
253-
254-
$usedTraitDependencies = $this->dependencyResolver->resolveUsedTraitDependencies($node);
255-
foreach ($usedTraitDependencies->getFileDependencies($scope->getFile(), $analysedFiles) as $dependentFile) {
256-
$usedTraitFileDependencies[] = $dependentFile;
257-
}
258-
};
259101

102+
$nodeCallback = new FileAnalyserCallback(
103+
$file,
104+
$analysedFiles,
105+
$ruleRegistry,
106+
$collectorRegistry,
107+
$outerNodeCallback,
108+
$parserNodes,
109+
$this->ignoreErrorExtensionProvider->getExtensions(),
110+
$this->parser,
111+
$this->dependencyResolver,
112+
$this->ruleErrorTransformer,
113+
$processedFiles,
114+
);
260115
$scope = $this->scopeFactory->create(ScopeContext::create($file), $nodeCallback);
261116
$nodeCallback(new FileNode($parserNodes), $scope);
262117
$this->nodeScopeResolver->processNodes(
263118
$parserNodes,
264119
$scope,
265120
$nodeCallback,
266121
);
122+
$fileErrors = $nodeCallback->getFileErrors();
123+
$fileCollectedData = $nodeCallback->getFileCollectedData();
124+
$fileDependencies = $nodeCallback->getFileDependencies();
125+
$usedTraitFileDependencies = $nodeCallback->getUsedTraitFileDependencies();
126+
$exportedNodes = $nodeCallback->getExportedNodes();
127+
$linesToIgnore = $nodeCallback->getLinesToIgnore();
128+
$unmatchedLineIgnores = $nodeCallback->getUnmatchedLineIgnores();
129+
$temporaryFileErrors = $nodeCallback->getTemporaryFileErrors();
130+
$processedFiles = $nodeCallback->getProcessedFiles();
267131

268132
$localIgnoresProcessorResult = $this->localIgnoresProcessor->process(
269133
$temporaryFileErrors,
@@ -345,20 +209,6 @@ public function analyseFile(
345209
);
346210
}
347211

348-
/**
349-
* @param Node[] $nodes
350-
* @return array<int, non-empty-list<string>|null>
351-
*/
352-
private function getLinesToIgnoreFromTokens(array $nodes): array
353-
{
354-
if (!isset($nodes[0])) {
355-
return [];
356-
}
357-
358-
/** @var array<int, non-empty-list<string>|null> */
359-
return $nodes[0]->getAttribute('linesToIgnore', []);
360-
}
361-
362212
/**
363213
* @param array<string, true> $analysedFiles
364214
*/

0 commit comments

Comments
 (0)