Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. ParsingFileAnalyser.php

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\StaticAnalysis
View 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&lt;string, array&lt;string, CodeUnitClassType&gt;&gt;
ParsingFileAnalyser::$executableLines private property
ParsingFileAnalyser::$functions private property @psalm-var array&lt;string, array&lt;string, CodeUnitFunctionType&gt;&gt;
ParsingFileAnalyser::$ignoreDeprecatedCode private property
ParsingFileAnalyser::$ignoredLines private property
ParsingFileAnalyser::$linesOfCode private property
ParsingFileAnalyser::$traits private property @psalm-var array&lt;string, array&lt;string, CodeUnitTraitType&gt;&gt;
ParsingFileAnalyser::$useAnnotationsForIgnoringCode private property
ParsingFileAnalyser::analyse private function
ParsingFileAnalyser::classesIn public function @psalm-return array&lt;string, CodeUnitClassType&gt; Overrides FileAnalyser::classesIn
ParsingFileAnalyser::executableLinesIn public function @psalm-return LinesType Overrides FileAnalyser::executableLinesIn
ParsingFileAnalyser::findLinesIgnoredByLineBasedAnnotations private function
ParsingFileAnalyser::functionsIn public function @psalm-return array&lt;string, CodeUnitFunctionType&gt; 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&lt;string, CodeUnitTraitType&gt; Overrides FileAnalyser::traitsIn
ParsingFileAnalyser::__construct public function

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal