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

Breadcrumb

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

class CodeUnitFindingVisitor

@internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage

@psalm-type CodeUnitFunctionType = array{ name: string, namespacedName: string, namespace: string, signature: string, startLine: int, endLine: int, ccn: int } @psalm-type CodeUnitMethodType = array{ methodName: string, signature: string, visibility: string, startLine: int, endLine: int, ccn: int } @psalm-type CodeUnitClassType = array{ name: string, namespacedName: string, namespace: string, startLine: int, endLine: int, methods: array<string, CodeUnitMethodType> } @psalm-type CodeUnitTraitType = array{ name: string, namespacedName: string, namespace: string, startLine: int, endLine: int, methods: array<string, CodeUnitMethodType> }

Hierarchy

  • class \PhpParser\NodeVisitorAbstract implements \PhpParser\NodeVisitor
    • class \SebastianBergmann\CodeCoverage\StaticAnalysis\CodeUnitFindingVisitor extends \PhpParser\NodeVisitorAbstract

Expanded class hierarchy of CodeUnitFindingVisitor

File

vendor/phpunit/php-code-coverage/src/StaticAnalysis/CodeUnitFindingVisitor.php, line 70

Namespace

SebastianBergmann\CodeCoverage\StaticAnalysis
View source
final class CodeUnitFindingVisitor extends NodeVisitorAbstract {
    
    /**
     * @psalm-var array<string, CodeUnitClassType>
     */
    private array $classes = [];
    
    /**
     * @psalm-var array<string, CodeUnitTraitType>
     */
    private array $traits = [];
    
    /**
     * @psalm-var array<string, CodeUnitFunctionType>
     */
    private array $functions = [];
    public function enterNode(Node $node) : void {
        if ($node instanceof Class_) {
            if ($node->isAnonymous()) {
                return;
            }
            $this->processClass($node);
        }
        if ($node instanceof Trait_) {
            $this->processTrait($node);
        }
        if (!$node instanceof ClassMethod && !$node instanceof Function_) {
            return;
        }
        if ($node instanceof ClassMethod) {
            $parentNode = $node->getAttribute('parent');
            if ($parentNode instanceof Class_ && $parentNode->isAnonymous()) {
                return;
            }
            $this->processMethod($node);
            return;
        }
        $this->processFunction($node);
    }
    
    /**
     * @psalm-return array<string, CodeUnitClassType>
     */
    public function classes() : array {
        return $this->classes;
    }
    
    /**
     * @psalm-return array<string, CodeUnitTraitType>
     */
    public function traits() : array {
        return $this->traits;
    }
    
    /**
     * @psalm-return array<string, CodeUnitFunctionType>
     */
    public function functions() : array {
        return $this->functions;
    }
    private function cyclomaticComplexity(ClassMethod|Function_ $node) : int {
        $nodes = $node->getStmts();
        if ($nodes === null) {
            return 0;
        }
        $traverser = new NodeTraverser();
        $cyclomaticComplexityCalculatingVisitor = new CyclomaticComplexityCalculatingVisitor();
        $traverser->addVisitor($cyclomaticComplexityCalculatingVisitor);
        
        /* @noinspection UnusedFunctionResultInspection */
        $traverser->traverse($nodes);
        return $cyclomaticComplexityCalculatingVisitor->cyclomaticComplexity();
    }
    private function signature(ClassMethod|Function_ $node) : string {
        $signature = ($node->returnsByRef() ? '&' : '') . $node->name
            ->toString() . '(';
        $parameters = [];
        foreach ($node->getParams() as $parameter) {
            assert(isset($parameter->var->name));
            $parameterAsString = '';
            if ($parameter->type !== null) {
                $parameterAsString = $this->type($parameter->type) . ' ';
            }
            $parameterAsString .= '$' . $parameter->var->name;
            
            /* @todo Handle default values */
            $parameters[] = $parameterAsString;
        }
        $signature .= implode(', ', $parameters) . ')';
        $returnType = $node->getReturnType();
        if ($returnType !== null) {
            $signature .= ': ' . $this->type($returnType);
        }
        return $signature;
    }
    private function type(ComplexType|Identifier|Name $type) : string {
        if ($type instanceof NullableType) {
            return '?' . $type->type;
        }
        if ($type instanceof UnionType) {
            return $this->unionTypeAsString($type);
        }
        if ($type instanceof IntersectionType) {
            return $this->intersectionTypeAsString($type);
        }
        return $type->toString();
    }
    private function visibility(ClassMethod $node) : string {
        if ($node->isPrivate()) {
            return 'private';
        }
        if ($node->isProtected()) {
            return 'protected';
        }
        return 'public';
    }
    private function processClass(Class_ $node) : void {
        $name = $node->name
            ->toString();
        $namespacedName = $node->namespacedName
            ->toString();
        $this->classes[$namespacedName] = [
            'name' => $name,
            'namespacedName' => $namespacedName,
            'namespace' => $this->namespace($namespacedName, $name),
            'startLine' => $node->getStartLine(),
            'endLine' => $node->getEndLine(),
            'methods' => [],
        ];
    }
    private function processTrait(Trait_ $node) : void {
        $name = $node->name
            ->toString();
        $namespacedName = $node->namespacedName
            ->toString();
        $this->traits[$namespacedName] = [
            'name' => $name,
            'namespacedName' => $namespacedName,
            'namespace' => $this->namespace($namespacedName, $name),
            'startLine' => $node->getStartLine(),
            'endLine' => $node->getEndLine(),
            'methods' => [],
        ];
    }
    private function processMethod(ClassMethod $node) : void {
        $parentNode = $node->getAttribute('parent');
        if ($parentNode instanceof Interface_) {
            return;
        }
        assert($parentNode instanceof Class_ || $parentNode instanceof Trait_ || $parentNode instanceof Enum_);
        assert(isset($parentNode->name));
        assert(isset($parentNode->namespacedName));
        assert($parentNode->namespacedName instanceof Name);
        $parentName = $parentNode->name
            ->toString();
        $parentNamespacedName = $parentNode->namespacedName
            ->toString();
        if ($parentNode instanceof Class_) {
            $storage =& $this->classes;
        }
        else {
            $storage =& $this->traits;
        }
        if (!isset($storage[$parentNamespacedName])) {
            $storage[$parentNamespacedName] = [
                'name' => $parentName,
                'namespacedName' => $parentNamespacedName,
                'namespace' => $this->namespace($parentNamespacedName, $parentName),
                'startLine' => $parentNode->getStartLine(),
                'endLine' => $parentNode->getEndLine(),
                'methods' => [],
            ];
        }
        $storage[$parentNamespacedName]['methods'][$node->name
            ->toString()] = [
            'methodName' => $node->name
                ->toString(),
            'signature' => $this->signature($node),
            'visibility' => $this->visibility($node),
            'startLine' => $node->getStartLine(),
            'endLine' => $node->getEndLine(),
            'ccn' => $this->cyclomaticComplexity($node),
        ];
    }
    private function processFunction(Function_ $node) : void {
        assert(isset($node->name));
        assert(isset($node->namespacedName));
        assert($node->namespacedName instanceof Name);
        $name = $node->name
            ->toString();
        $namespacedName = $node->namespacedName
            ->toString();
        $this->functions[$namespacedName] = [
            'name' => $name,
            'namespacedName' => $namespacedName,
            'namespace' => $this->namespace($namespacedName, $name),
            'signature' => $this->signature($node),
            'startLine' => $node->getStartLine(),
            'endLine' => $node->getEndLine(),
            'ccn' => $this->cyclomaticComplexity($node),
        ];
    }
    private function namespace(string $namespacedName, string $name) : string {
        return trim(rtrim($namespacedName, $name), '\\');
    }
    private function unionTypeAsString(UnionType $node) : string {
        $types = [];
        foreach ($node->types as $type) {
            if ($type instanceof IntersectionType) {
                $types[] = '(' . $this->intersectionTypeAsString($type) . ')';
                continue;
            }
            $types[] = $this->typeAsString($type);
        }
        return implode('|', $types);
    }
    private function intersectionTypeAsString(IntersectionType $node) : string {
        $types = [];
        foreach ($node->types as $type) {
            $types[] = $this->typeAsString($type);
        }
        return implode('&', $types);
    }
    private function typeAsString(Identifier|Name $node) : string {
        if ($node instanceof Name) {
            return $node->toCodeString();
        }
        return $node->toString();
    }

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title Overrides
CodeUnitFindingVisitor::$classes private property @psalm-var array&lt;string, CodeUnitClassType&gt;
CodeUnitFindingVisitor::$functions private property @psalm-var array&lt;string, CodeUnitFunctionType&gt;
CodeUnitFindingVisitor::$traits private property @psalm-var array&lt;string, CodeUnitTraitType&gt;
CodeUnitFindingVisitor::classes public function @psalm-return array&lt;string, CodeUnitClassType&gt;
CodeUnitFindingVisitor::cyclomaticComplexity private function
CodeUnitFindingVisitor::enterNode public function Called when entering a node. Overrides NodeVisitorAbstract::enterNode
CodeUnitFindingVisitor::functions public function @psalm-return array&lt;string, CodeUnitFunctionType&gt;
CodeUnitFindingVisitor::intersectionTypeAsString private function
CodeUnitFindingVisitor::namespace private function
CodeUnitFindingVisitor::processClass private function
CodeUnitFindingVisitor::processFunction private function
CodeUnitFindingVisitor::processMethod private function
CodeUnitFindingVisitor::processTrait private function
CodeUnitFindingVisitor::signature private function
CodeUnitFindingVisitor::traits public function @psalm-return array&lt;string, CodeUnitTraitType&gt;
CodeUnitFindingVisitor::type private function
CodeUnitFindingVisitor::typeAsString private function
CodeUnitFindingVisitor::unionTypeAsString private function
CodeUnitFindingVisitor::visibility private function
NodeVisitor::DONT_TRAVERSE_CHILDREN public constant If NodeVisitor::enterNode() returns DONT_TRAVERSE_CHILDREN, child nodes
of the current node will not be traversed for any visitors.
NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN public constant If NodeVisitor::enterNode() returns DONT_TRAVERSE_CURRENT_AND_CHILDREN, child nodes
of the current node will not be traversed for any visitors.
NodeVisitor::REMOVE_NODE public constant If NodeVisitor::leaveNode() returns REMOVE_NODE for a node that occurs
in an array, it will be removed from the array.
NodeVisitor::REPLACE_WITH_NULL public constant If NodeVisitor::enterNode() or NodeVisitor::leaveNode() returns REPLACE_WITH_NULL,
the node will be replaced with null. This is not a legal return value if the node is part
of an array, rather than another node.
NodeVisitor::STOP_TRAVERSAL public constant If NodeVisitor::enterNode() or NodeVisitor::leaveNode() returns
STOP_TRAVERSAL, traversal is aborted.
NodeVisitorAbstract::afterTraverse public function Called once after traversal. Overrides NodeVisitor::afterTraverse 1
NodeVisitorAbstract::beforeTraverse public function Called once before traversal. Overrides NodeVisitor::beforeTraverse 5
NodeVisitorAbstract::leaveNode public function Called when leaving a node. Overrides NodeVisitor::leaveNode 2

API Navigation

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