class ParsingFileAnalyser
@internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage
@psalm-import-type CodeUnitFunctionType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor @psalm-import-type CodeUnitMethodType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor @psalm-import-type CodeUnitClassType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor @psalm-import-type CodeUnitTraitType from \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor @psalm-import-type LinesOfCodeType from \SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser @psalm-import-type LinesType from \SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser
Hierarchy
- class \SebastianBergmann\CodeCoverage\StaticAnalysis\ParsingFileAnalyser implements \SebastianBergmann\CodeCoverage\StaticAnalysis\FileAnalyser
Expanded class hierarchy of ParsingFileAnalyser
1 file declares its use of ParsingFileAnalyser
- CodeCoverage.php in vendor/
phpunit/ php-code-coverage/ src/ CodeCoverage.php
File
-
vendor/
phpunit/ php-code-coverage/ src/ StaticAnalysis/ ParsingFileAnalyser.php, line 42
Namespace
SebastianBergmann\CodeCoverage\StaticAnalysisView source
final class ParsingFileAnalyser implements FileAnalyser {
/**
* @psalm-var array<string, array<string, CodeUnitClassType>>
*/
private array $classes = [];
/**
* @psalm-var array<string, array<string, CodeUnitTraitType>>
*/
private array $traits = [];
/**
* @psalm-var array<string, array<string, CodeUnitFunctionType>>
*/
private array $functions = [];
/**
* @var array<string, LinesOfCodeType>
*/
private array $linesOfCode = [];
/**
* @var array<string, LinesType>
*/
private array $ignoredLines = [];
/**
* @var array<string, LinesType>
*/
private array $executableLines = [];
private readonly bool $useAnnotationsForIgnoringCode;
private readonly bool $ignoreDeprecatedCode;
public function __construct(bool $useAnnotationsForIgnoringCode, bool $ignoreDeprecatedCode) {
$this->useAnnotationsForIgnoringCode = $useAnnotationsForIgnoringCode;
$this->ignoreDeprecatedCode = $ignoreDeprecatedCode;
}
public function classesIn(string $filename) : array {
$this->analyse($filename);
return $this->classes[$filename];
}
public function traitsIn(string $filename) : array {
$this->analyse($filename);
return $this->traits[$filename];
}
public function functionsIn(string $filename) : array {
$this->analyse($filename);
return $this->functions[$filename];
}
public function linesOfCodeFor(string $filename) : array {
$this->analyse($filename);
return $this->linesOfCode[$filename];
}
public function executableLinesIn(string $filename) : array {
$this->analyse($filename);
return $this->executableLines[$filename];
}
public function ignoredLinesFor(string $filename) : array {
$this->analyse($filename);
return $this->ignoredLines[$filename];
}
/**
* @throws ParserException
*/
private function analyse(string $filename) : void {
if (isset($this->classes[$filename])) {
return;
}
$source = file_get_contents($filename);
$linesOfCode = max(substr_count($source, "\n") + 1, substr_count($source, "\r") + 1);
if ($linesOfCode === 0 && !empty($source)) {
$linesOfCode = 1;
}
assert($linesOfCode > 0);
$parser = (new ParserFactory())->createForHostVersion();
try {
$nodes = $parser->parse($source);
assert($nodes !== null);
$traverser = new NodeTraverser();
$codeUnitFindingVisitor = new CodeUnitFindingVisitor();
$lineCountingVisitor = new LineCountingVisitor($linesOfCode);
$ignoredLinesFindingVisitor = new IgnoredLinesFindingVisitor($this->useAnnotationsForIgnoringCode, $this->ignoreDeprecatedCode);
$executableLinesFindingVisitor = new ExecutableLinesFindingVisitor($source);
$traverser->addVisitor(new NameResolver());
$traverser->addVisitor(new ParentConnectingVisitor());
$traverser->addVisitor($codeUnitFindingVisitor);
$traverser->addVisitor($lineCountingVisitor);
$traverser->addVisitor($ignoredLinesFindingVisitor);
$traverser->addVisitor($executableLinesFindingVisitor);
/* @noinspection UnusedFunctionResultInspection */
$traverser->traverse($nodes);
// @codeCoverageIgnoreStart
} catch (Error $error) {
throw new ParserException(sprintf('Cannot parse %s: %s', $filename, $error->getMessage()), $error->getCode(), $error);
}
// @codeCoverageIgnoreEnd
$this->classes[$filename] = $codeUnitFindingVisitor->classes();
$this->traits[$filename] = $codeUnitFindingVisitor->traits();
$this->functions[$filename] = $codeUnitFindingVisitor->functions();
$this->executableLines[$filename] = $executableLinesFindingVisitor->executableLinesGroupedByBranch();
$this->ignoredLines[$filename] = [];
$this->findLinesIgnoredByLineBasedAnnotations($filename, $source, $this->useAnnotationsForIgnoringCode);
$this->ignoredLines[$filename] = array_unique(array_merge($this->ignoredLines[$filename], $ignoredLinesFindingVisitor->ignoredLines()));
sort($this->ignoredLines[$filename]);
$result = $lineCountingVisitor->result();
$this->linesOfCode[$filename] = [
'linesOfCode' => $result->linesOfCode(),
'commentLinesOfCode' => $result->commentLinesOfCode(),
'nonCommentLinesOfCode' => $result->nonCommentLinesOfCode(),
];
}
private function findLinesIgnoredByLineBasedAnnotations(string $filename, string $source, bool $useAnnotationsForIgnoringCode) : void {
if (!$useAnnotationsForIgnoringCode) {
return;
}
$start = false;
foreach (token_get_all($source) as $token) {
if (!is_array($token) || !(T_COMMENT === $token[0] || T_DOC_COMMENT === $token[0])) {
continue;
}
$comment = trim($token[1]);
if ($comment === '// @codeCoverageIgnore' || $comment === '//@codeCoverageIgnore') {
$this->ignoredLines[$filename][] = $token[2];
continue;
}
if ($comment === '// @codeCoverageIgnoreStart' || $comment === '//@codeCoverageIgnoreStart') {
$start = $token[2];
continue;
}
if ($comment === '// @codeCoverageIgnoreEnd' || $comment === '//@codeCoverageIgnoreEnd') {
if (false === $start) {
$start = $token[2];
}
$this->ignoredLines[$filename] = array_merge($this->ignoredLines[$filename], range($start, $token[2]));
}
}
}
}
Members
Title Sort descending | Modifiers | Object type | Summary | Overriden Title |
---|---|---|---|---|
ParsingFileAnalyser::$classes | private | property | @psalm-var array<string, array<string, CodeUnitClassType>> | |
ParsingFileAnalyser::$executableLines | private | property | ||
ParsingFileAnalyser::$functions | private | property | @psalm-var array<string, array<string, CodeUnitFunctionType>> | |
ParsingFileAnalyser::$ignoreDeprecatedCode | private | property | ||
ParsingFileAnalyser::$ignoredLines | private | property | ||
ParsingFileAnalyser::$linesOfCode | private | property | ||
ParsingFileAnalyser::$traits | private | property | @psalm-var array<string, array<string, CodeUnitTraitType>> | |
ParsingFileAnalyser::$useAnnotationsForIgnoringCode | private | property | ||
ParsingFileAnalyser::analyse | private | function | ||
ParsingFileAnalyser::classesIn | public | function | @psalm-return array<string, CodeUnitClassType> | Overrides FileAnalyser::classesIn |
ParsingFileAnalyser::executableLinesIn | public | function | @psalm-return LinesType | Overrides FileAnalyser::executableLinesIn |
ParsingFileAnalyser::findLinesIgnoredByLineBasedAnnotations | private | function | ||
ParsingFileAnalyser::functionsIn | public | function | @psalm-return array<string, CodeUnitFunctionType> | Overrides FileAnalyser::functionsIn |
ParsingFileAnalyser::ignoredLinesFor | public | function | @psalm-return LinesType | Overrides FileAnalyser::ignoredLinesFor |
ParsingFileAnalyser::linesOfCodeFor | public | function | @psalm-return LinesOfCodeType | Overrides FileAnalyser::linesOfCodeFor |
ParsingFileAnalyser::traitsIn | public | function | @psalm-return array<string, CodeUnitTraitType> | Overrides FileAnalyser::traitsIn |
ParsingFileAnalyser::__construct | public | function |