![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/ |
<?php /** * This file is part of PDepend. * * PHP Version 5 * * Copyright (c) 2008-2017 Manuel Pichler <[email protected]>. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of Manuel Pichler nor the names of his * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @copyright 2008-2017 Manuel Pichler. All rights reserved. * @license http://www.opensource.org/licenses/bsd-license.php BSD License */ namespace PDepend\Source\Language\PHP; use BadMethodCallException; use PDepend\Source\AST\AbstractASTClassOrInterface; use PDepend\Source\AST\AbstractASTNode; use PDepend\Source\AST\AbstractASTType; use PDepend\Source\AST\ASTAllocationExpression; use PDepend\Source\AST\ASTAnonymousClass; use PDepend\Source\AST\ASTArguments; use PDepend\Source\AST\ASTArray; use PDepend\Source\AST\ASTArrayElement; use PDepend\Source\AST\ASTArrayIndexExpression; use PDepend\Source\AST\ASTArtifactList; use PDepend\Source\AST\ASTAssignmentExpression; use PDepend\Source\AST\ASTBooleanAndExpression; use PDepend\Source\AST\ASTBooleanOrExpression; use PDepend\Source\AST\ASTBreakStatement; use PDepend\Source\AST\ASTCastExpression; use PDepend\Source\AST\ASTCatchStatement; use PDepend\Source\AST\ASTClass; use PDepend\Source\AST\ASTClassFqnPostfix; use PDepend\Source\AST\ASTClassOrInterfaceReference; use PDepend\Source\AST\ASTClassReference; use PDepend\Source\AST\ASTCloneExpression; use PDepend\Source\AST\ASTClosure; use PDepend\Source\AST\ASTComment; use PDepend\Source\AST\ASTCompilationUnit; use PDepend\Source\AST\ASTCompoundExpression; use PDepend\Source\AST\ASTCompoundVariable; use PDepend\Source\AST\ASTConditionalExpression; use PDepend\Source\AST\ASTConstant; use PDepend\Source\AST\ASTConstantDeclarator; use PDepend\Source\AST\ASTConstantDefinition; use PDepend\Source\AST\ASTConstantPostfix; use PDepend\Source\AST\ASTContinueStatement; use PDepend\Source\AST\ASTDeclareStatement; use PDepend\Source\AST\ASTDoWhileStatement; use PDepend\Source\AST\ASTEchoStatement; use PDepend\Source\AST\ASTElseIfStatement; use PDepend\Source\AST\ASTEnum; use PDepend\Source\AST\ASTEnumCase; use PDepend\Source\AST\ASTEvalExpression; use PDepend\Source\AST\ASTExitExpression; use PDepend\Source\AST\ASTExpression; use PDepend\Source\AST\ASTFieldDeclaration; use PDepend\Source\AST\ASTFinallyStatement; use PDepend\Source\AST\ASTForeachStatement; use PDepend\Source\AST\ASTForInit; use PDepend\Source\AST\ASTFormalParameter; use PDepend\Source\AST\ASTFormalParameters; use PDepend\Source\AST\ASTForStatement; use PDepend\Source\AST\ASTForUpdate; use PDepend\Source\AST\ASTFunction; use PDepend\Source\AST\ASTFunctionPostfix; use PDepend\Source\AST\ASTGlobalStatement; use PDepend\Source\AST\ASTGotoStatement; use PDepend\Source\AST\ASTHeredoc; use PDepend\Source\AST\ASTIdentifier; use PDepend\Source\AST\ASTIfStatement; use PDepend\Source\AST\ASTIncludeExpression; use PDepend\Source\AST\ASTInstanceOfExpression; use PDepend\Source\AST\ASTInterface; use PDepend\Source\AST\ASTIntersectionType; use PDepend\Source\AST\ASTIssetExpression; use PDepend\Source\AST\ASTLabelStatement; use PDepend\Source\AST\ASTListExpression; use PDepend\Source\AST\ASTLiteral; use PDepend\Source\AST\ASTLogicalAndExpression; use PDepend\Source\AST\ASTLogicalOrExpression; use PDepend\Source\AST\ASTLogicalXorExpression; use PDepend\Source\AST\ASTMatchArgument; use PDepend\Source\AST\ASTMatchBlock; use PDepend\Source\AST\ASTMatchEntry; use PDepend\Source\AST\ASTMemberPrimaryPrefix; use PDepend\Source\AST\ASTMethod; use PDepend\Source\AST\ASTMethodPostfix; use PDepend\Source\AST\ASTNamedArgument; use PDepend\Source\AST\ASTNamespace; use PDepend\Source\AST\ASTNode; use PDepend\Source\AST\ASTParentReference; use PDepend\Source\AST\ASTPostfixExpression; use PDepend\Source\AST\ASTPreDecrementExpression; use PDepend\Source\AST\ASTPreIncrementExpression; use PDepend\Source\AST\ASTPrintExpression; use PDepend\Source\AST\ASTPropertyPostfix; use PDepend\Source\AST\ASTRequireExpression; use PDepend\Source\AST\ASTReturnStatement; use PDepend\Source\AST\ASTScalarType; use PDepend\Source\AST\ASTScope; use PDepend\Source\AST\ASTScopeStatement; use PDepend\Source\AST\ASTSelfReference; use PDepend\Source\AST\ASTShiftLeftExpression; use PDepend\Source\AST\ASTShiftRightExpression; use PDepend\Source\AST\ASTStatement; use PDepend\Source\AST\ASTStaticReference; use PDepend\Source\AST\ASTStaticVariableDeclaration; use PDepend\Source\AST\ASTString; use PDepend\Source\AST\ASTStringIndexExpression; use PDepend\Source\AST\ASTSwitchLabel; use PDepend\Source\AST\ASTSwitchStatement; use PDepend\Source\AST\ASTThrowStatement; use PDepend\Source\AST\ASTTrait; use PDepend\Source\AST\ASTTraitAdaptation; use PDepend\Source\AST\ASTTraitAdaptationAlias; use PDepend\Source\AST\ASTTraitAdaptationPrecedence; use PDepend\Source\AST\ASTTraitReference; use PDepend\Source\AST\ASTTraitUseStatement; use PDepend\Source\AST\ASTTryStatement; use PDepend\Source\AST\ASTTypeArray; use PDepend\Source\AST\ASTTypeCallable; use PDepend\Source\AST\ASTTypeIterable; use PDepend\Source\AST\ASTUnaryExpression; use PDepend\Source\AST\ASTUnionType; use PDepend\Source\AST\ASTUnsetStatement; use PDepend\Source\AST\ASTVariable; use PDepend\Source\AST\ASTVariableDeclarator; use PDepend\Source\AST\ASTVariableVariable; use PDepend\Source\AST\ASTWhileStatement; use PDepend\Source\AST\ASTYieldStatement; use PDepend\Source\Builder\Builder; use PDepend\Source\Builder\BuilderContext; use PDepend\Source\Builder\BuilderContext\GlobalBuilderContext; use PDepend\Util\Cache\CacheDriver; use PDepend\Util\Log; use PDepend\Util\Type; use ReturnTypeWillChange; /** * Default code tree builder implementation. * * @copyright 2008-2017 Manuel Pichler. All rights reserved. * @license http://www.opensource.org/licenses/bsd-license.php BSD License * * @implements Builder<ASTNamespace> */ class PHPBuilder implements Builder { /** * The internal used cache instance. * * @var CacheDriver * * @since 0.10.0 */ protected $cache = null; /** * The ast builder context. * * @var BuilderContext * * @since 0.10.0 */ protected $context = null; /** * This property holds all packages found during the parsing phase. * * @var ASTNamespace[] * * @since 0.9.12 */ private $preparedNamespaces = null; /** * Default package which contains all functions and classes with an unknown * scope. * * @var ASTNamespace */ protected $defaultPackage = null; /** * Default source file that acts as a dummy. * * @var ASTCompilationUnit */ protected $defaultCompilationUnit = null; /** * All generated {@link ASTTrait} objects * * @var array<string, array<string, array<int, ASTTrait>>> */ private $traits = array(); /** * All generated {@link ASTClass} objects * * @var array<string, array<string, array<int, ASTClass>>> */ private $classes = array(); /** * All generated {@link ASTInterface} instances. * * @var array<string, array<string, array<int, ASTInterface>>> */ private $interfaces = array(); /** * All generated {@link ASTNamespace} objects * * @var ASTNamespace[] */ private $namespaces = array(); /** * Internal status flag used to check that a build request is internal. * * @var bool */ private $internal = false; /** * Internal used flag that marks the parsing process as frozen. * * @var bool */ private $frozen = false; /** * Cache of all traits created during the regular parsing process. * * @var array<string, array<string, array<int, ASTTrait>>> */ private $frozenTraits = array(); /** * Cache of all classes created during the regular parsing process. * * @var array<string, array<string, array<int, ASTClass>>> */ private $frozenClasses = array(); /** * Cache of all interfaces created during the regular parsing process. * * @var array<string, array<string, array<int, ASTInterface>>> */ private $frozenInterfaces = array(); /** * Constructs a new builder instance. */ public function __construct() { $this->defaultPackage = new ASTNamespace(self::DEFAULT_NAMESPACE); $this->defaultCompilationUnit = new ASTCompilationUnit(null); $this->namespaces[self::DEFAULT_NAMESPACE] = $this->defaultPackage; $this->context = new GlobalBuilderContext($this); } /** * Setter method for the currently used token cache. * * @return $this * * @since 0.10.0 */ public function setCache(CacheDriver $cache) { $this->cache = $cache; return $this; } /** * Builds a new code type reference instance. * * @param string $qualifiedName The qualified name of the referenced type. * * @return ASTClassOrInterfaceReference * * @since 0.9.5 */ public function buildAstClassOrInterfaceReference($qualifiedName) { $this->checkBuilderState(); // Debug method creation Log::debug( 'Creating: \\PDepend\\Source\\AST\\ASTClassOrInterfaceReference(' . $qualifiedName . ')' ); return new ASTClassOrInterfaceReference($this->context, $qualifiedName); } /** * Builds a new code type reference instance, either Class or ClassOrInterface. * * @param string $qualifiedName The qualified name of the referenced type. * @param bool $classReference true if class reference only. * * @return ASTClassOrInterfaceReference * * @since 0.9.5 */ public function buildAstNeededReference($qualifiedName, $classReference) { if ($classReference === true) { return $this->buildAstClassReference($qualifiedName); } return $this->buildAstClassOrInterfaceReference($qualifiedName); } /** * This method will try to find an already existing instance for the given * qualified name. It will create a new {@link ASTClass} * instance when no matching type exists. * * @param string $qualifiedName * * @return AbstractASTClassOrInterface * * @since 0.9.5 */ public function getClassOrInterface($qualifiedName) { $classOrInterface = $this->findClass($qualifiedName); if ($classOrInterface !== null) { return $classOrInterface; } $classOrInterface = $this->findInterface($qualifiedName); if ($classOrInterface !== null) { return $classOrInterface; } return $this->buildClassInternal($qualifiedName); } /** * Builds a new php trait instance. * * @param string $qualifiedName The full qualified trait name. * * @return ASTTrait * * @since 1.0.0 */ public function buildTrait($qualifiedName) { $this->checkBuilderState(); $trait = new ASTTrait($this->extractTypeName($qualifiedName)); $trait->setCache($this->cache) ->setContext($this->context) ->setCompilationUnit($this->defaultCompilationUnit); return $trait; } /** * This method will try to find an already existing instance for the given * qualified name. It will create a new {@link ASTTrait} * instance when no matching type exists. * * @param string $qualifiedName * * @return ASTTrait * * @since 1.0.0 */ public function getTrait($qualifiedName) { $trait = $this->findTrait($qualifiedName); if ($trait === null) { $trait = $this->buildTraitInternal($qualifiedName); } return $trait; } /** * Builds a new trait reference node. * * @param string $qualifiedName The full qualified trait name. * * @return ASTTraitReference * * @since 1.0.0 */ public function buildAstTraitReference($qualifiedName) { $this->checkBuilderState(); Log::debug( 'Creating: \\PDepend\\Source\\AST\\ASTTraitReference(' . $qualifiedName . ')' ); return new ASTTraitReference($this->context, $qualifiedName); } /** * Builds a new class instance or reuses a previous created class. * * Where possible you should give a qualified class name, that is prefixed * with the package identifier. * * <code> * $builder->buildClass('php::depend::Parser'); * </code> * * To determine the correct class, this method implements the following * algorithm. * * <ol> * <li>Check for an exactly matching instance and reuse it.</li> * <li>Check for a class instance that belongs to the default package. If * such an instance exists, reuse it and replace the default package with * the newly given package information.</li> * <li>Check that the requested class is in the default package, if this * is true, reuse the first class instance and ignore the default package. * </li> * <li>Create a new instance for the specified package.</li> * </ol> * * @param string $name The class name. * * @return ASTClass The created class object. */ public function buildClass($name) { $this->checkBuilderState(); $class = new ASTClass($this->extractTypeName($name)); $class->setCache($this->cache) ->setContext($this->context) ->setCompilationUnit($this->defaultCompilationUnit); return $class; } /** * This method will try to find an already existing instance for the given * qualified name. It will create a new {@link ASTClass} * instance when no matching type exists. * * @param string $qualifiedName The full qualified type identifier. * * @return ASTClass * * @since 0.9.5 */ public function getClass($qualifiedName) { return $this->findClass($qualifiedName) ?: $this->buildClassInternal($qualifiedName); } /** * Builds an anonymous class instance. * * @return ASTAnonymousClass */ public function buildAnonymousClass() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTAnonymousClass') ->setCache($this->cache) ->setContext($this->context); } /** * Builds a new code type reference instance. * * @param string $qualifiedName The qualified name of the referenced type. * * @return ASTClassReference * * @since 0.9.5 */ public function buildAstClassReference($qualifiedName) { $this->checkBuilderState(); // Debug method creation Log::debug( 'Creating: \\PDepend\\Source\\AST\\ASTClassReference(' . $qualifiedName . ')' ); return new ASTClassReference($this->context, $qualifiedName); } /** * Builds a new new interface instance. * * If there is an existing class instance for the given name, this method * checks if this class is part of the default namespace. If this is the * case this method will update all references to the new interface and it * removes the class instance. Otherwise it creates new interface instance. * * Where possible you should give a qualified interface name, that is * prefixed with the package identifier. * * <code> * $builder->buildInterface('php::depend::Parser'); * </code> * * To determine the correct interface, this method implements the following * algorithm. * * <ol> * <li>Check for an exactly matching instance and reuse it.</li> * <li>Check for a interface instance that belongs to the default package. * If such an instance exists, reuse it and replace the default package * with the newly given package information.</li> * <li>Check that the requested interface is in the default package, if * this is true, reuse the first interface instance and ignore the default * package. * </li> * <li>Create a new instance for the specified package.</li> * </ol> * * @param string $name The interface name. * * @return ASTInterface */ public function buildInterface($name) { $this->checkBuilderState(); $interface = new ASTInterface($this->extractTypeName($name)); $interface->setCache($this->cache) ->setContext($this->context) ->setCompilationUnit($this->defaultCompilationUnit); return $interface; } /** * This method will try to find an already existing instance for the given * qualified name. It will create a new {@link ASTInterface} * instance when no matching type exists. * * @param string $qualifiedName * * @return ASTInterface * * @since 0.9.5 */ public function getInterface($qualifiedName) { $interface = $this->findInterface($qualifiedName); if ($interface === null) { $interface = $this->buildInterfaceInternal($qualifiedName); } return $interface; } /** * Builds a new method instance. * * @param string $name * * @return ASTMethod */ public function buildMethod($name) { $this->checkBuilderState(); // Debug method creation Log::debug("Creating: \\PDepend\\Source\\AST\\ASTMethod({$name})"); // Create a new method instance $method = new ASTMethod($name); $method->setCache($this->cache); return $method; } /** * Builds a new package instance. * * @param string $name The package name. * * @return ASTNamespace */ public function buildNamespace($name) { if (!isset($this->namespaces[$name])) { // Debug package creation Log::debug( 'Creating: \\PDepend\\Source\\AST\\ASTNamespace(' . $name . ')' ); $this->namespaces[$name] = new ASTNamespace($name); } return $this->namespaces[$name]; } /** * Builds a new function instance. * * @param string $name The function name. * * @return ASTFunction */ public function buildFunction($name) { $this->checkBuilderState(); // Debug function creation Log::debug("Creating: \\PDepend\\Source\\AST\\ASTFunction({$name})"); // Create new function $function = new ASTFunction($name); $function->setCache($this->cache) ->setContext($this->context) ->setCompilationUnit($this->defaultCompilationUnit); return $function; } /** * Builds a new self reference instance. * * @return ASTSelfReference * * @since 0.9.6 */ public function buildAstSelfReference(AbstractASTClassOrInterface $type) { Log::debug( 'Creating: \\PDepend\\Source\\AST\\ASTSelfReference(' . $type->getName() . ')' ); return new ASTSelfReference($this->context, $type); } /** * Builds a new parent reference instance. * * @param ASTClassOrInterfaceReference $reference The type * instance that reference the concrete target of parent. * * @return ASTParentReference * * @since 0.9.6 */ public function buildAstParentReference(ASTClassOrInterfaceReference $reference) { Log::debug('Creating: \\PDepend\\Source\\AST\\ASTParentReference()'); return new ASTParentReference($reference); } /** * Builds a new static reference instance. * * @return ASTStaticReference * * @since 0.9.6 */ public function buildAstStaticReference(AbstractASTClassOrInterface $owner) { Log::debug('Creating: \\PDepend\\Source\\AST\\ASTStaticReference()'); return new ASTStaticReference($this->context, $owner); } /** * Builds a new field declaration node. * * @return ASTFieldDeclaration * * @since 0.9.6 */ public function buildAstFieldDeclaration() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTFieldDeclaration'); } /** * Builds a new variable declarator node. * * @param string $image The source image for the variable declarator. * * @return ASTVariableDeclarator * * @since 0.9.6 */ public function buildAstVariableDeclarator($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTVariableDeclarator', $image); } /** * Builds a new static variable declaration node. * * @param string $image The source image for the statuc declaration. * * @return ASTStaticVariableDeclaration * * @since 0.9.6 */ public function buildAstStaticVariableDeclaration($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTStaticVariableDeclaration', $image); } /** * Builds a new constant node. * * @param string $image The source image for the constant. * * @return ASTConstant * * @since 0.9.6 */ public function buildAstConstant($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTConstant', $image); } /** * Builds a new variable node. * * @param string $image The source image for the variable. * * @return ASTVariable * * @since 0.9.6 */ public function buildAstVariable($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTVariable', $image); } /** * Builds a new variable variable node. * * @param string $image The source image for the variable variable. * * @return ASTVariableVariable * * @since 0.9.6 */ public function buildAstVariableVariable($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTVariableVariable', $image); } /** * Builds a new compound variable node. * * @param string $image The source image for the compound variable. * * @return ASTCompoundVariable * * @since 0.9.6 */ public function buildAstCompoundVariable($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTCompoundVariable', $image); } /** * Builds a new compound expression node. * * @return ASTCompoundExpression * * @since 0.9.6 */ public function buildAstCompoundExpression() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTCompoundExpression'); } /** * Builds a new closure node. * * @return ASTClosure * * @since 0.9.12 */ public function buildAstClosure() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTClosure'); } /** * Builds a new formal parameters node. * * @return ASTFormalParameters * * @since 0.9.6 */ public function buildAstFormalParameters() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTFormalParameters'); } /** * Builds a new formal parameter node. * * @return ASTFormalParameter * * @since 0.9.6 */ public function buildAstFormalParameter() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTFormalParameter'); } /** * Builds a new expression node. * * @param string $image * * @return ASTExpression * * @since 0.9.8 */ public function buildAstExpression($image = null) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTExpression', $image); } /** * Builds a new assignment expression node. * * @param string $image The assignment operator. * * @return ASTAssignmentExpression * * @since 0.9.8 */ public function buildAstAssignmentExpression($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTAssignmentExpression', $image); } /** * Builds a new allocation expression node. * * @param string $image The source image of this expression. * * @return ASTAllocationExpression * * @since 0.9.6 */ public function buildAstAllocationExpression($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTAllocationExpression', $image); } /** * Builds a new eval-expression node. * * @param string $image The source image of this expression. * * @return ASTEvalExpression * * @since 0.9.12 */ public function buildAstEvalExpression($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTEvalExpression', $image); } /** * Builds a new exit-expression instance. * * @param string $image The source code image for this node. * * @return ASTExitExpression * * @since 0.9.12 */ public function buildAstExitExpression($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTExitExpression', $image); } /** * Builds a new clone-expression node. * * @param string $image The source image of this expression. * * @return ASTCloneExpression * * @since 0.9.12 */ public function buildAstCloneExpression($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTCloneExpression', $image); } /** * Builds a new list-expression node. * * @param string $image The source image of this expression. * * @return ASTListExpression * * @since 0.9.12 */ public function buildAstListExpression($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTListExpression', $image); } /** * Builds a new include- or include_once-expression. * * @return ASTIncludeExpression * * @since 0.9.12 */ public function buildAstIncludeExpression() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTIncludeExpression'); } /** * Builds a new require- or require_once-expression. * * @return ASTRequireExpression * * @since 0.9.12 */ public function buildAstRequireExpression() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTRequireExpression'); } /** * Builds a new array-expression node. * * @return ASTArrayIndexExpression * * @since 0.9.12 */ public function buildAstArrayIndexExpression() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTArrayIndexExpression'); } /** * Builds a new string-expression node. * * <code> * // -------- * $string{$index} * // -------- * </code> * * @return ASTStringIndexExpression * * @since 0.9.12 */ public function buildAstStringIndexExpression() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTStringIndexExpression'); } /** * Builds a new php array node. * * @return ASTArray * * @since 1.0.0 */ public function buildAstArray() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTArray'); } /** * Builds a new array element node. * * @return ASTArrayElement * * @since 1.0.0 */ public function buildAstArrayElement() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTArrayElement'); } /** * Builds a new instanceof expression node. * * @param string $image The source image of this expression. * * @return ASTInstanceOfExpression * * @since 0.9.6 */ public function buildAstInstanceOfExpression($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTInstanceOfExpression', $image); } /** * Builds a new isset-expression node. * * <code> * // ----------- * if (isset($foo)) { * // ----------- * } * * // ----------------------- * if (isset($foo, $bar, $baz)) { * // ----------------------- * } * </code> * * @return ASTIssetExpression * * @since 0.9.12 */ public function buildAstIssetExpression() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTIssetExpression'); } /** * Builds a new boolean conditional-expression. * * <code> * -------------- * $bar = ($foo ? 42 : 23); * -------------- * </code> * * @return ASTConditionalExpression * * @since 0.9.8 */ public function buildAstConditionalExpression() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTConditionalExpression', '?'); } /** * Builds a new print-expression. * * <code> * ------------- * print "qafoo"; * ------------- * </code> * * @return ASTPrintExpression * * @since 2.3 */ public function buildAstPrintExpression() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTPrintExpression', 'print'); } /** * Build a new shift left expression. * * @return ASTShiftLeftExpression * * @since 1.0.1 */ public function buildAstShiftLeftExpression() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTShiftLeftExpression'); } /** * Build a new shift right expression. * * @return ASTShiftRightExpression * * @since 1.0.1 */ public function buildAstShiftRightExpression() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTShiftRightExpression'); } /** * Builds a new boolean and-expression. * * @return ASTBooleanAndExpression * * @since 0.9.8 */ public function buildAstBooleanAndExpression() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTBooleanAndExpression', '&&'); } /** * Builds a new boolean or-expression. * * @return ASTBooleanOrExpression * * @since 0.9.8 */ public function buildAstBooleanOrExpression() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTBooleanOrExpression', '||'); } /** * Builds a new logical <b>and</b>-expression. * * @return ASTLogicalAndExpression * * @since 0.9.8 */ public function buildAstLogicalAndExpression() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTLogicalAndExpression', 'and'); } /** * Builds a new logical <b>or</b>-expression. * * @return ASTLogicalOrExpression * * @since 0.9.8 */ public function buildAstLogicalOrExpression() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTLogicalOrExpression', 'or'); } /** * Builds a new logical <b>xor</b>-expression. * * @return ASTLogicalXorExpression * * @since 0.9.8 */ public function buildAstLogicalXorExpression() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTLogicalXorExpression', 'xor'); } /** * Builds a new trait use-statement node. * * @return ASTTraitUseStatement * * @since 1.0.0 */ public function buildAstTraitUseStatement() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTTraitUseStatement'); } /** * Builds a new trait adaptation scope * * @return ASTTraitAdaptation * * @since 1.0.0 */ public function buildAstTraitAdaptation() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTTraitAdaptation'); } /** * Builds a new trait adaptation alias statement. * * @param string $image The trait method name. * * @return ASTTraitAdaptationAlias * * @since 1.0.0 */ public function buildAstTraitAdaptationAlias($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTTraitAdaptationAlias', $image); } /** * Builds a new trait adaptation precedence statement. * * @param string $image The trait method name. * * @return ASTTraitAdaptationPrecedence * * @since 1.0.0 */ public function buildAstTraitAdaptationPrecedence($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTTraitAdaptationPrecedence', $image); } /** * Builds a new switch-statement-node. * * @return ASTSwitchStatement * * @since 0.9.8 */ public function buildAstSwitchStatement() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTSwitchStatement'); } /** * Builds a new switch-label node. * * @param string $image The source image of this label. * * @return ASTSwitchLabel * * @since 0.9.8 */ public function buildAstSwitchLabel($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTSwitchLabel', $image); } /** * Builds a new global-statement instance. * * @return ASTGlobalStatement * * @since 0.9.12 */ public function buildAstGlobalStatement() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTGlobalStatement'); } /** * Builds a new unset-statement instance. * * @return ASTUnsetStatement * * @since 0.9.12 */ public function buildAstUnsetStatement() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTUnsetStatement'); } /** * Builds a new catch-statement node. * * @param string $image * * @return ASTCatchStatement * * @since 0.9.8 */ public function buildAstCatchStatement($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTCatchStatement', $image); } /** * Builds a new finally-statement node. * * @return ASTFinallyStatement * * @since 2.0.0 */ public function buildAstFinallyStatement() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTFinallyStatement', 'finally'); } /** * Builds a new if statement node. * * @param string $image The source image of this statement. * * @return ASTIfStatement * * @since 0.9.8 */ public function buildAstIfStatement($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTIfStatement', $image); } /** * Builds a new elseif statement node. * * @param string $image The source image of this statement. * * @return ASTElseIfStatement * * @since 0.9.8 */ public function buildAstElseIfStatement($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTElseIfStatement', $image); } /** * Builds a new for statement node. * * @param string $image The source image of this statement. * * @return ASTForStatement * * @since 0.9.8 */ public function buildAstForStatement($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTForStatement', $image); } /** * Builds a new for-init node. * * <code> * ------------------------ * for ($x = 0, $y = 23, $z = 42; $x < $y; ++$x) {} * ------------------------ * </code> * * @return ASTForInit * * @since 0.9.8 */ public function buildAstForInit() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTForInit'); } /** * Builds a new for-update node. * * <code> * ------------------------------- * for ($x = 0, $y = 23, $z = 42; $x < $y; ++$x, $y = $x + 1, $z = $x + 2) {} * ------------------------------- * </code> * * @return ASTForUpdate * * @since 0.9.12 */ public function buildAstForUpdate() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTForUpdate'); } /** * Builds a new foreach-statement node. * * @param string $image The source image of this statement. * * @return ASTForeachStatement * * @since 0.9.8 */ public function buildAstForeachStatement($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTForeachStatement', $image); } /** * Builds a new while-statement node. * * @param string $image The source image of this statement. * * @return ASTWhileStatement * * @since 0.9.8 */ public function buildAstWhileStatement($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTWhileStatement', $image); } /** * Builds a new do/while-statement node. * * @param string $image The source image of this statement. * * @return ASTDoWhileStatement * * @since 0.9.12 */ public function buildAstDoWhileStatement($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTDoWhileStatement', $image); } /** * Builds a new declare-statement node. * * <code> * ------------------------------- * declare(encoding='ISO-8859-1'); * ------------------------------- * * ------------------- * declare(ticks=42) { * // ... * } * - * * ------------------ * declare(ticks=42): * // ... * enddeclare; * ----------- * </code> * * @return ASTDeclareStatement * * @since 0.10.0 */ public function buildAstDeclareStatement() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTDeclareStatement'); } /** * Builds a new member primary expression node. * * <code> * //-------- * Foo::bar(); * //-------- * * //--------- * Foo::$bar(); * //--------- * * //--------- * $obj->bar(); * //--------- * * //---------- * $obj->$bar(); * //---------- * </code> * * @param string $image The source image of this expression. * * @return ASTMemberPrimaryPrefix * * @since 0.9.6 */ public function buildAstMemberPrimaryPrefix($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTMemberPrimaryPrefix', $image); } /** * Builds a new identifier node. * * @param string $image The image of this identifier. * * @return ASTIdentifier * * @since 0.9.6 */ public function buildAstIdentifier($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTIdentifier', $image); } /** * Builds a new function postfix expression. * * <code> * //------- * foo($bar); * //------- * * //-------- * $foo($bar); * //-------- * </code> * * @param string $image The image of this node. * * @return ASTFunctionPostfix * * @since 0.9.6 */ public function buildAstFunctionPostfix($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTFunctionPostfix', $image); } /** * Builds a new method postfix expression. * * <code> * // --------- * Foo::bar($baz); * // --------- * * // ---------- * Foo::$bar($baz); * // ---------- * </code> * * @param string $image The image of this node. * * @return ASTMethodPostfix * * @since 0.9.6 */ public function buildAstMethodPostfix($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTMethodPostfix', $image); } /** * Builds a new constant postfix expression. * * <code> * // --- * Foo::BAR; * // --- * </code> * * @param string $image The image of this node. * * @return ASTConstantPostfix * * @since 0.9.6 */ public function buildAstConstantPostfix($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTConstantPostfix', $image); } /** * Builds a new property postfix expression. * * <code> * // ---- * Foo::$bar; * // ---- * * // --- * $object->bar; * // --- * </code> * * @param string $image The image of this node. * * @return ASTPropertyPostfix * * @since 0.9.6 */ public function buildAstPropertyPostfix($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTPropertyPostfix', $image); } /** * Builds a new full qualified class name postfix expression. * * <code> * // ----- * Foo::class; * // ----- * * // ----- * $object::class; * // ----- * </code> * * @return ASTClassFqnPostfix * * @since 2.0.0 */ public function buildAstClassFqnPostfix() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTClassFqnPostfix', 'class'); } /** * Builds a new arguments list. * * <code> * // ------------ * Foo::bar($x, $y, $z); * // ------------ * * // ------------ * $foo->bar($x, $y, $z); * // ------------ * </code> * * @return ASTArguments * * @since 0.9.6 */ public function buildAstArguments() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTArguments'); } /** * Builds a new argument match expression single-item slot. * * <code> * match($x) * </code> * * @return ASTMatchArgument * * @since 0.9.6 */ public function buildAstMatchArgument() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTMatchArgument'); } /** * Builds a new match block. * * <code> * match($x) { * "foo" => "bar", * } * </code> * * @return ASTMatchBlock * * @since 2.9.0 */ public function buildAstMatchBlock() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTMatchBlock'); } /** * Builds a new match item. * * <code> * "foo" => "bar", * </code> * * @return ASTMatchEntry * * @since 2.9.0 */ public function buildAstMatchEntry() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTMatchEntry'); } /** * Builds a new named argument node. * * <code> * number_format(5623, thousands_separator: ' ') * </code> * * @param string $name * * @return ASTNamedArgument * * @since 2.9.0 */ public function buildAstNamedArgument($name, ASTNode $value) { Log::debug("Creating: \\PDepend\\Source\\AST\\ASTNamedArgument($name)"); return new ASTNamedArgument($name, $value); } /** * Builds a new array type node. * * @return ASTTypeArray * * @since 0.9.6 */ public function buildAstTypeArray() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTTypeArray'); } /** * Builds a new node for the callable type. * * @return ASTTypeCallable * * @since 1.0.0 */ public function buildAstTypeCallable() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTTypeCallable'); } /** * Builds a new node for the iterable type. * * @return ASTTypeIterable * * @since 2.5.1 */ public function buildAstTypeIterable() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTTypeIterable'); } /** * Builds a new primitive type node. * * @param string $image The source image for the primitive type. * * @return ASTScalarType * * @since 0.9.6 */ public function buildAstScalarType($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTScalarType', $image); } /** * Builds a new node for the union type. * * @return ASTUnionType * * @since 1.0.0 */ public function buildAstUnionType() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTUnionType'); } /** * Builds a new node for the union type. * * @return ASTIntersectionType */ public function buildAstIntersectionType() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTIntersectionType'); } /** * Builds a new literal node. * * @param string $image The source image for the literal node. * * @return ASTLiteral * * @since 0.9.6 */ public function buildAstLiteral($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTLiteral', $image); } /** * Builds a new php string node. * * <code> * $string = "Manuel $Pichler <{$email}>"; * * // ASTString * // |-- ASTLiteral - "Manuel ") * // |-- ASTVariable - $Pichler * // |-- ASTLiteral - " <" * // |-- ASTCompoundExpression - {...} * // | |-- ASTVariable - $email * // |-- ASTLiteral - ">" * </code> * * @return ASTString * * @since 0.9.10 */ public function buildAstString() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTString'); } /** * Builds a new heredoc node. * * @return ASTHeredoc * * @since 0.9.12 */ public function buildAstHeredoc() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTHeredoc'); } /** * Builds a new constant definition node. * * <code> * class Foo * { * // ------------------------ * const FOO = 42, BAR = 23; * // ------------------------ * } * </code> * * @param string $image The source code image for this node. * * @return ASTConstantDefinition * * @since 0.9.6 */ public function buildAstConstantDefinition($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTConstantDefinition', $image); } /** * Builds a new constant declarator node. * * <code> * class Foo * { * // -------- * const BAR = 42; * // -------- * } * </code> * * Or in a comma separated constant defintion: * * <code> * class Foo * { * // -------- * const BAR = 42, * // -------- * * // -------------- * const BAZ = 'Foobar', * // -------------- * * // ---------- * const FOO = 3.14; * // ---------- * } * </code> * * @param string $image The source code image for this node. * * @return ASTConstantDeclarator * * @since 0.9.6 */ public function buildAstConstantDeclarator($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTConstantDeclarator', $image); } /** * Builds a new comment node instance. * * @param string $cdata The comment text. * * @return ASTComment * * @since 0.9.8 */ public function buildAstComment($cdata) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTComment', $cdata); } /** * Builds a new unary expression node instance. * * @param string $image The unary expression image/character. * * @return ASTUnaryExpression * * @since 0.9.11 */ public function buildAstUnaryExpression($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTUnaryExpression', $image); } /** * Builds a new cast-expression node instance. * * @param string $image The cast-expression image/character. * * @return ASTCastExpression * * @since 0.10.0 */ public function buildAstCastExpression($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTCastExpression', $image); } /** * Builds a new postfix-expression node instance. * * @param string $image The postfix-expression image/character. * * @return ASTPostfixExpression * * @since 0.10.0 */ public function buildAstPostfixExpression($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTPostfixExpression', $image); } /** * Builds a new pre-increment-expression node instance. * * @return ASTPreIncrementExpression * * @since 0.10.0 */ public function buildAstPreIncrementExpression() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTPreIncrementExpression'); } /** * Builds a new pre-decrement-expression node instance. * * @return ASTPreDecrementExpression * * @since 0.10.0 */ public function buildAstPreDecrementExpression() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTPreDecrementExpression'); } /** * Builds a new function/method scope instance. * * @return ASTScope * * @since 0.9.12 */ public function buildAstScope() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTScope'); } /** * Builds a new statement instance. * * @return ASTStatement * * @since 0.9.12 */ public function buildAstStatement() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTStatement'); } /** * Builds a new return statement node instance. * * @param string $image The source code image for this node. * * @return ASTReturnStatement * * @since 0.9.12 */ public function buildAstReturnStatement($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTReturnStatement', $image); } /** * Builds a new break-statement node instance. * * @param string $image The source code image for this node. * * @return ASTBreakStatement * * @since 0.9.12 */ public function buildAstBreakStatement($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTBreakStatement', $image); } /** * Builds a new continue-statement node instance. * * @param string $image The source code image for this node. * * @return ASTContinueStatement * * @since 0.9.12 */ public function buildAstContinueStatement($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTContinueStatement', $image); } /** * Builds a new scope-statement instance. * * @return ASTScopeStatement * * @since 0.9.12 */ public function buildAstScopeStatement() { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTScopeStatement'); } /** * Builds a new try-statement instance. * * @param string $image The source code image for this node. * * @return ASTTryStatement * * @since 0.9.12 */ public function buildAstTryStatement($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTTryStatement', $image); } /** * Builds a new throw-statement instance. * * @param string $image The source code image for this node. * * @return ASTThrowStatement * * @since 0.9.12 */ public function buildAstThrowStatement($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTThrowStatement', $image); } /** * Builds a new goto-statement instance. * * @param string $image The source code image for this node. * * @return ASTGotoStatement * * @since 0.9.12 */ public function buildAstGotoStatement($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTGotoStatement', $image); } /** * Builds a new label-statement instance. * * @param string $image The source code image for this node. * * @return ASTLabelStatement * * @since 0.9.12 */ public function buildAstLabelStatement($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTLabelStatement', $image); } /** * Builds a new exit-statement instance. * * @param string $image The source code image for this node. * * @return ASTEchoStatement * * @since 0.9.12 */ public function buildAstEchoStatement($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTEchoStatement', $image); } /** * Builds a new yield-statement instance. * * @param string $image The source code image for this node. * * @return ASTYieldStatement * * @since $version$ */ public function buildAstYieldStatement($image) { return $this->buildAstNodeInstance('\\PDepend\\Source\\AST\\ASTYieldStatement', $image); } /** * Returns an iterator with all generated {@link ASTNamespace} * objects. * * @return ASTArtifactList<ASTNamespace> */ #[ReturnTypeWillChange] public function getIterator() { return $this->getNamespaces(); } /** * Returns an iterator with all generated {@link ASTNamespace} * objects. * * @return ASTArtifactList<ASTNamespace> */ public function getNamespaces() { if ($this->preparedNamespaces === null) { $this->preparedNamespaces = $this->getPreparedNamespaces(); } return new ASTArtifactList($this->preparedNamespaces); } /** * Returns an iterator with all generated {@link ASTNamespace} * objects. * * @return ASTNamespace[] * * @since 0.9.12 */ private function getPreparedNamespaces() { // Create a package array copy $namespaces = $this->namespaces; // Remove default package if empty if (count($this->defaultPackage->getTypes()) === 0 && count($this->defaultPackage->getFunctions()) === 0 ) { unset($namespaces[self::DEFAULT_NAMESPACE]); } return $namespaces; } /** * Builds a new trait instance or reuses a previous created trait. * * Where possible you should give a qualified trait name, that is prefixed * with the package identifier. * * <code> * $builder->buildTrait('php::depend::Parser'); * </code> * * To determine the correct trait, this method implements the following * algorithm. * * <ol> * <li>Check for an exactly matching instance and reuse it.</li> * <li>Check for a class instance that belongs to the default package. If * such an instance exists, reuse it and replace the default package with * the newly given package information.</li> * <li>Check that the requested trait is in the default package, if this * is true, reuse the first trait instance and ignore the default package. * </li> * <li>Create a new instance for the specified package.</li> * </ol> * * @param string $qualifiedName * * @return ASTTrait * * @since 0.9.5 */ protected function buildTraitInternal($qualifiedName) { $this->internal = true; $trait = $this->buildTrait($qualifiedName); $trait->setNamespace( $this->buildNamespace($this->extractNamespaceName($qualifiedName)) ); $this->restoreTrait($trait); return $trait; } /** * This method tries to find a trait instance matching for the given * qualified name in all scopes already processed. It will return the best * matching instance or <b>null</b> if no match exists. * * @param string $qualifiedName * * @return ASTTrait|null * * @since 0.9.5 */ protected function findTrait($qualifiedName) { $this->freeze(); /** @var ASTTrait|null $trait */ $trait = $this->findType( $this->frozenTraits, $qualifiedName ); if ($trait === null) { $trait = $this->findType($this->traits, $qualifiedName); } return $trait; } /** * Builds a new new interface instance. * * If there is an existing interface instance for the given name, this method * checks if this interface is part of the default namespace. If this is the * case this method will update all references to the new interface and it * removes the class instance. Otherwise it creates new interface instance. * * Where possible you should give a qualified interface name, that is * prefixed with the package identifier. * * <code> * $builder->buildInterface('php::depend::Parser'); * </code> * * To determine the correct interface, this method implements the following * algorithm. * * <ol> * <li>Check for an exactly matching instance and reuse it.</li> * <li>Check for a interface instance that belongs to the default package. * If such an instance exists, reuse it and replace the default package * with the newly given package information.</li> * <li>Check that the requested interface is in the default package, if * this is true, reuse the first interface instance and ignore the default * package. * </li> * <li>Create a new instance for the specified package.</li> * </ol> * * @param string $qualifiedName * * @return ASTInterface * * @since 0.9.5 */ protected function buildInterfaceInternal($qualifiedName) { $this->internal = true; $interface = $this->buildInterface($qualifiedName); $interface->setNamespace( $this->buildNamespace($this->extractNamespaceName($qualifiedName)) ); $this->restoreInterface($interface); return $interface; } /** * This method tries to find an interface instance matching for the given * qualified name in all scopes already processed. It will return the best * matching instance or <b>null</b> if no match exists. * * @param string $qualifiedName * * @return ASTInterface|null * * @since 0.9.5 */ protected function findInterface($qualifiedName) { $this->freeze(); /** @var ASTInterface|null $interface */ $interface = $this->findType( $this->frozenInterfaces, $qualifiedName ); if ($interface === null) { $interface = $this->findType( $this->interfaces, $qualifiedName ); } return $interface; } /** * Builds a new class instance or reuses a previous created class. * * Where possible you should give a qualified class name, that is prefixed * with the package identifier. * * <code> * $builder->buildClass('php::depend::Parser'); * </code> * * To determine the correct class, this method implements the following * algorithm. * * <ol> * <li>Check for an exactly matching instance and reuse it.</li> * <li>Check for a class instance that belongs to the default package. If * such an instance exists, reuse it and replace the default package with * the newly given package information.</li> * <li>Check that the requested class is in the default package, if this * is true, reuse the first class instance and ignore the default package. * </li> * <li>Create a new instance for the specified package.</li> * </ol> * * @param string $qualifiedName * * @return ASTClass * * @since 0.9.5 */ protected function buildClassInternal($qualifiedName) { $this->internal = true; $class = $this->buildClass($qualifiedName); $class->setNamespace( $this->buildNamespace($this->extractNamespaceName($qualifiedName)) ); $this->restoreClass($class); return $class; } /** * This method tries to find a class instance matching for the given * qualified name in all scopes already processed. It will return the best * matching instance or <b>null</b> if no match exists. * * @param string $qualifiedName * * @return ASTClass|null * * @since 0.9.5 */ protected function findClass($qualifiedName) { $this->freeze(); /** @var ASTClass|null $class */ $class = $this->findType( $this->frozenClasses, $qualifiedName ); if ($class === null) { $class = $this->findType($this->classes, $qualifiedName); } return $class; } /** * This method tries to find an interface or class instance matching for the * given qualified name in all scopes already processed. It will return the * best matching instance or <b>null</b> if no match exists. * * @template T of AbstractASTType * * @param array<string, array<string, array<int, T>>> $instances * @param string $qualifiedName * * @return T|null * * @since 0.9.5 */ protected function findType(array $instances, $qualifiedName) { $classOrInterfaceName = $this->extractTypeName($qualifiedName); $caseInsensitiveName = strtolower($classOrInterfaceName); if (!isset($instances[$caseInsensitiveName])) { return null; } $namespaceName = $this->extractNamespaceName($qualifiedName); if ($namespaceName === null) { return null; } // Check for exact match and return first matching instance if (isset($instances[$caseInsensitiveName][$namespaceName])) { return reset($instances[$caseInsensitiveName][$namespaceName]) ?: null; } if (!$this->isDefault($namespaceName)) { return null; } $classesOrInterfaces = reset($instances[$caseInsensitiveName]); if (!$classesOrInterfaces) { return null; } return reset($classesOrInterfaces); } /** * This method will freeze the actual builder state and create a second * runtime scope. * * @return void * * @since 0.9.5 */ protected function freeze() { if ($this->frozen === true) { return; } $this->frozen = true; $this->frozenTraits = $this->copyTypesWithPackage($this->traits); $this->frozenClasses = $this->copyTypesWithPackage($this->classes); $this->frozenInterfaces = $this->copyTypesWithPackage($this->interfaces); $this->traits = array(); $this->classes = array(); $this->interfaces = array(); } /** * Creates a copy of the given input array, but skips all types that do not * contain a parent package. * * @template T of AbstractASTType * * @param array<string, array<string, array<int, T>>> $originalTypes The original types created during the parsing * process. * * @return array<string, array<string, array<int, T>>> */ private function copyTypesWithPackage(array $originalTypes) { $copiedTypes = array(); foreach ($originalTypes as $typeName => $namespaces) { foreach ($namespaces as $namespaceName => $types) { foreach ($types as $index => $type) { $copiedTypes[$typeName][$namespaceName][$index] = $type; } } } return $copiedTypes; } /** * Restores a function within the internal type scope. * * @return void * * @since 0.10.0 */ public function restoreFunction(ASTFunction $function) { $this->buildNamespace($function->getNamespaceName()) ->addFunction($function); } /** * Restores a trait within the internal type scope. * * @return void * * @since 0.10.0 */ public function restoreTrait(ASTTrait $trait) { $this->storeTrait( $trait->getName(), $trait->getNamespaceName(), $trait ); } /** * Restores a class within the internal type scope. * * @return void * * @since 0.10.0 */ public function restoreClass(ASTClass $class) { $this->storeClass( $class->getName(), $class->getNamespaceName(), $class ); } /** * Restores an enum within the internal type scope. * * @return void * * @since 2.11.0 */ public function restoreEnum(ASTEnum $enum) { $this->storeEnum( $enum->getName(), $enum->getNamespaceName(), $enum ); } /** * Restores an interface within the internal type scope. * * @return void * * @since 0.10.0 */ public function restoreInterface(ASTInterface $interface) { $this->storeInterface( $interface->getName(), $interface->getNamespaceName(), $interface ); } /** * Builds an enum definition. * * @param string $name The enum name. * @param ASTScalarType $type The enum type ('string', 'int', or null if not backed). * * @return ASTEnum The created class object. */ public function buildEnum($name, ASTScalarType $type = null) { $this->checkBuilderState(); $enum = new ASTEnum($name, $type); $enum->setCache($this->cache) ->setContext($this->context) ->setCompilationUnit($this->defaultCompilationUnit); return $enum; } /** * Builds an enum definition. * * @param string $name The enum case name. * @param AbstractASTNode $value The enum case value if backed. * * @return ASTEnumCase The created class object. */ public function buildEnumCase($name, AbstractASTNode $value = null) { $this->checkBuilderState(); $enumCase = new ASTEnumCase($name); if ($value !== null) { $enumCase->addChild($value); } return $enumCase; } /** * This method will persist a trait instance for later reuse. * * @param string $traitName * @param string $namespaceName * * @return void * * @since 1.0.0 */ protected function storeTrait($traitName, $namespaceName, ASTTrait $trait) { $traitName = strtolower($traitName); if (!isset($this->traits[$traitName][$namespaceName])) { $this->traits[$traitName][$namespaceName] = array(); } $this->traits[$traitName][$namespaceName][$trait->getId()] = $trait; $namespace = $this->buildNamespace($namespaceName); $namespace->addType($trait); } /** * This method will persist a class instance for later reuse. * * @param string $className * @param string $namespaceName * * @return void * * @since 0.9.5 */ protected function storeClass($className, $namespaceName, ASTClass $class) { $className = strtolower($className); if (!isset($this->classes[$className][$namespaceName])) { $this->classes[$className][$namespaceName] = array(); } $this->classes[$className][$namespaceName][$class->getId()] = $class; $namespace = $this->buildNamespace($namespaceName); $namespace->addType($class); } /** * This method will persist a class instance for later reuse. * * @param string $enumName * @param string $namespaceName * * @return void * * @since 2.11.0 */ protected function storeEnum($enumName, $namespaceName, ASTEnum $enum) { $enumName = strtolower($enumName); if (!isset($this->classes[$enumName][$namespaceName])) { $this->classes[$enumName][$namespaceName] = array(); } $this->classes[$enumName][$namespaceName][$enum->getId()] = $enum; $namespace = $this->buildNamespace($namespaceName); $namespace->addType($enum); } /** * This method will persist an interface instance for later reuse. * * @param string $interfaceName * @param string $namespaceName * * @return void * * @since 0.9.5 */ protected function storeInterface($interfaceName, $namespaceName, ASTInterface $interface) { $interfaceName = strtolower($interfaceName); if (!isset($this->interfaces[$interfaceName][$namespaceName])) { $this->interfaces[$interfaceName][$namespaceName] = array(); } $this->interfaces[$interfaceName][$namespaceName][$interface->getId()] = $interface; $namespace = $this->buildNamespace($namespaceName); $namespace->addType($interface); } /** * Checks that the parser is not frozen or a request is flagged as internal. * * @param bool $internal The new internal flag value. * * @throws BadMethodCallException * * @return void * * @since 0.9.5 */ protected function checkBuilderState($internal = false) { if ($this->frozen === true && $this->internal === false) { throw new BadMethodCallException( 'Cannot create new nodes, when internal state is frozen.' ); } $this->internal = $internal; } /** * Returns <b>true</b> if the given package is the default package. * * @param string $namespaceName The package name. * * @return bool */ protected function isDefault($namespaceName) { return ($namespaceName === self::DEFAULT_NAMESPACE); } /** * Extracts the type name of a qualified PHP 5.3 type identifier. * * <code> * $typeName = $this->extractTypeName('foo\bar\foobar'); * var_dump($typeName); * // Results in: * // string(6) "foobar" * </code> * * @param string $qualifiedName The qualified PHP 5.3 type identifier. * * @return string */ protected function extractTypeName($qualifiedName) { if (($pos = strrpos($qualifiedName, '\\')) !== false) { return substr($qualifiedName, $pos + 1); } return $qualifiedName; } /** * Extracts the package name of a qualified PHP 5.3 class identifier. * * If the class name doesn't contain a package identifier this method will * return the default identifier. * * <code> * $namespaceName = $this->extractPackageName('foo\bar\foobar'); * var_dump($namespaceName); * // Results in: * // string(8) "foo\bar" * * $namespaceName = $this->extractPackageName('foobar'); * var_dump($namespaceName); * // Results in: * // string(6) "+global" * </code> * * @param string $qualifiedName The qualified PHP 5.3 class identifier. * * @return string|null */ protected function extractNamespaceName($qualifiedName) { if (($pos = strrpos($qualifiedName, '\\')) !== false) { return ltrim(substr($qualifiedName, 0, $pos), '\\'); } elseif (Type::isInternalType($qualifiedName)) { return Type::getTypePackage($qualifiedName); } return self::DEFAULT_NAMESPACE; } /** * Creates a {@link ASTNode} instance. * * @template T of ASTNode * * @param class-string<T> $className * @param string $image * * @return T * * @since 0.9.12 */ private function buildAstNodeInstance($className, $image = null) { Log::debug("Creating: {$className}({$image})"); return new $className($image); } }