/** * @param string[] $files * @param \Closure|null $progressCallback * @return string[]|\PHPStan\Analyser\Error[] errors */ public function analyse(array $files, \Closure $progressCallback = null) : array { $errors = []; if ($this->bootstrapFile !== null) { if (!is_file($this->bootstrapFile)) { return [sprintf('Bootstrap file %s does not exist.', $this->bootstrapFile)]; } try { require_once $this->bootstrapFile; } catch (\Throwable $e) { return [$e->getMessage()]; } } foreach ($this->ignoreErrors as $ignoreError) { try { \Nette\Utils\Strings::match('', $ignoreError); } catch (\Nette\Utils\RegexpException $e) { $errors[] = $e->getMessage(); } } if (count($errors) > 0) { return $errors; } foreach ($files as $file) { try { if ($this->isExcludedFromAnalysing($file)) { if ($progressCallback !== null) { $progressCallback($file); } continue; } $fileErrors = []; $this->nodeScopeResolver->processNodes($this->parser->parseFile($file), new Scope($this->broker, $this->printer, $file), function (\PhpParser\Node $node, Scope $scope) use(&$fileErrors) { if ($node instanceof \PhpParser\Node\Stmt\Trait_) { return; } $classes = array_merge([get_class($node)], class_parents($node)); foreach ($this->registry->getRules($classes) as $rule) { $ruleErrors = $this->createErrors($node, $scope->getAnalysedContextFile(), $rule->processNode($node, $scope)); $fileErrors = array_merge($fileErrors, $ruleErrors); } }); if ($progressCallback !== null) { $progressCallback($file); } $errors = array_merge($errors, $fileErrors); } catch (\PhpParser\Error $e) { $errors[] = new Error($e->getMessage(), $file); } catch (\PHPStan\AnalysedCodeException $e) { $errors[] = new Error($e->getMessage(), $file); } catch (\Throwable $t) { $errors[] = new Error(sprintf('Internal error: %s', $t->getMessage()), $file); } } $unmatchedIgnoredErrors = $this->ignoreErrors; $errors = array_values(array_filter($errors, function (string $error) use(&$unmatchedIgnoredErrors) : bool { foreach ($this->ignoreErrors as $i => $ignore) { if (\Nette\Utils\Strings::match($error, $ignore) !== null) { unset($unmatchedIgnoredErrors[$i]); return false; } } return true; })); foreach ($unmatchedIgnoredErrors as $unmatchedIgnoredError) { $errors[] = sprintf('Ignored error pattern %s was not matched in reported errors.', $unmatchedIgnoredError); } return $errors; }