상속: extends PhpParser\Node\Stmt, implements PhpParser\Node\FunctionLike
예제 #1
0
 /**
  * @param Context $context
  * @return boolean|null
  */
 public function compile(Context $context)
 {
     $this->compiled = true;
     $context->scopePointer = $this->getPointer();
     if ($this->statement->getDocComment() === null) {
         $context->notice('missing-docblock', sprintf('Missing docblock for %s() method', $this->name), $this->statement);
     }
     /**
      * It's not needed to compile empty method via it's abstract
      */
     if ($this->isAbstract()) {
         /** @var ClassDefinition $scope */
         $scope = $context->scope;
         if (!$scope->isAbstract()) {
             $context->notice('not-abstract-class-with-abstract-method', 'Class must be an abstract', $this->statement);
         }
         return true;
     }
     if (count($this->statement->stmts) == 0) {
         return $context->notice('not-implemented-method', sprintf('Method %s() is not implemented', $this->name), $this->statement);
     }
     if (count($this->statement->params) > 0) {
         /** @var  Node\Param $parameter */
         foreach ($this->statement->params as $parameter) {
             $context->addSymbol($parameter->name);
         }
     }
     foreach ($this->statement->stmts as $st) {
         \PHPSA\nodeVisitorFactory($st, $context);
     }
 }
예제 #2
0
 private function enterClassMethod(ClassMethod $node)
 {
     $methodName = $node->name;
     if ($this->isGetterOrSetter($methodName) !== true && $this->isNeitherConstructorNorDestructor($methodName)) {
         $this->methods[$methodName] = $node->isPublic();
     }
 }
예제 #3
0
 /**
  * Parses ClassMethod node to MethodData
  *
  * @return MethodData
  */
 public function parse(ClassMethod $node)
 {
     $method = new MethodData($node->name);
     $method->startLine = $node->getAttribute("startLine");
     $method->endLine = $node->getAttribute("endLine");
     $method->setType($node->type);
     $comments = $node->getAttribute("comments");
     if (is_array($comments)) {
         /** @var Comment */
         $comment = $this->commentParser->parse($comments[count($comments) - 1]->getText());
         if ($comment->isInheritDoc()) {
             $method->doc = Comment::INHERIT_MARK;
         } else {
             $method->doc = $comment->getDoc();
             $method->return = $comment->getReturn();
             foreach ($comment->getVars() as $var) {
                 if ($var instanceof MethodParam) {
                     $method->addParam($var);
                 }
             }
         }
     }
     foreach ($node->params as $child) {
         if ($child instanceof Param) {
             $method->addParam($this->parseMethodArgument($child));
         }
     }
     return $method;
 }
예제 #4
0
 protected function enterPublicMethod($fqcn, Stmt\ClassMethod $node)
 {
     $methodName = $node->name;
     $index = "{$fqcn}::{$methodName}";
     // create implemenation node
     // if not abstract we add the vertex for the implementation
     if (!$node->isAbstract()) {
         $this->pushImplementation($node, $index);
     }
     // push param for implementation, these parameters will be connected
     // to copy-pasted signature (see below)
     foreach ($node->params as $order => $aParam) {
         $this->pushParameter($index, $order);
     }
     // copy paste this signature in every class which use this current trait
     // Anyway we check if there is no other parent which declaring first this method
     $traitUser = $this->getReflectionContext()->getClassesUsingTraitForDeclaringMethod($fqcn, $methodName);
     foreach ($traitUser as $classname) {
         // we copy-paste the signature declaration in the class which using the current trait
         $index = $classname . '::' . $methodName;
         if (!$this->getGraphContext()->existsVertex('method', $index)) {
             $v = new MethodVertex($index);
             $this->getGraph()->addVertex($v);
             $this->getGraphContext()->indicesVertex('method', $index, $v);
         }
         // we do not copy-paste the parameters, there will be connected to original parameters from trait (see above)
     }
 }
예제 #5
0
 /**
  * @param ClassMethod $node
  *
  * @return NULL|\phpDocumentor\Reflection\DocBlock
  */
 private function nodeToDocBlock(ClassMethod $node)
 {
     $attribute = $node->getAttributes();
     if (isset($attribute['comments']) === false || isset($attribute['comments'][0]) === false) {
         return;
     }
     $docBlock = $attribute['comments'][0]->getText();
     return new DocBlock($docBlock);
 }
 public function testItContainsAMessageWhenReturnTypeChanged()
 {
     $test = new ReturnTypeChanged();
     $old = new ClassMethod('foo');
     $old->returnType = 'void if seal is broken';
     $class = new Class_('the_class');
     $class->namespacedName = $class->name;
     $old->setAttribute('parent', $class);
     $test->handle($old, new ClassMethod('foo'));
     $this->assertContains('changed return type', $test->lastException->getMessage());
 }
예제 #7
0
 public function testItIsFalseWhenNothingChanged()
 {
     $test = new BodyChanged();
     $func = new ClassMethod('some_method');
     $class = new Class_('the_class');
     $class->namespacedName = $class->name;
     $func->setAttribute('parent', $class);
     $old = $func;
     $new = $func;
     $this->assertFalse($test->handle($func, $old, $new));
 }
 /**
  * @param ClassMethod $node
  * @param Doc         $docComment
  */
 private function reapplyModifiedNode(ClassMethod $node, Doc $docComment)
 {
     $attributes = $node->getAttributes();
     $comments = isset($attributes['comments']) ? $attributes['comments'] : [];
     $lastComment = count($comments) ? $comments[count($comments) - 1] : null;
     if (!$lastComment instanceof Doc) {
         $comments[] = $docComment;
     } else {
         $comments[count($comments) - 1] = $docComment;
     }
     $node->setAttribute('comments', $comments);
 }
 public function testItReturnTrueWhenReturnTypeRemoved()
 {
     $test = new ReturnTypeRemoved();
     $old = new ClassMethod('foo');
     $old->returnType = 'void if seal is broken';
     $class = new Class_('the_class');
     $class->namespacedName = $class->name;
     $old->setAttribute('parent', $class);
     $new = new ClassMethod('foo');
     $this->assertTrue('' == (string) $new->getReturnType());
     $this->assertTrue($test->handle($old, $new));
 }
 public function visitMethod(ClassMethod $node)
 {
     $m = new PhpMethod($node->name);
     $m->setAbstract($node->isAbstract());
     $m->setFinal($node->isFinal());
     $m->setVisibility($this->getVisibility($node));
     $m->setStatic($node->isStatic());
     $m->setReferenceReturned($node->returnsByRef());
     // docblock
     if (($doc = $node->getDocComment()) !== null) {
         $m->setDocblock($doc->getReformattedText());
         $docblock = $m->getDocblock();
         $m->setDescription($docblock->getShortDescription());
         $m->setLongDescription($docblock->getLongDescription());
     }
     // params
     $params = $m->getDocblock()->getTags('param');
     foreach ($node->params as $param) {
         /* @var $param Param */
         $p = new PhpParameter();
         $p->setName($param->name);
         $p->setPassedByReference($param->byRef);
         if (is_string($param->type)) {
             $p->setType($param->type);
         } else {
             if ($param->type instanceof Name) {
                 $p->setType(implode('\\', $param->type->parts));
             }
         }
         $this->parseValue($p, $param);
         $tag = $params->find($p, function (ParamTag $t, $p) {
             return $t->getVariable() == '$' . $p->getName();
         });
         if ($tag !== null) {
             $p->setType($tag->getType(), $tag->getDescription());
         }
         $m->addParameter($p);
     }
     // return type and description
     $returns = $m->getDocblock()->getTags('return');
     if ($returns->size() > 0) {
         $return = $returns->get(0);
         $m->setType($return->getType(), $return->getDescription());
     }
     // body
     $stmts = $node->getStmts();
     if (is_array($stmts) && count($stmts)) {
         $prettyPrinter = new PrettyPrinter();
         $m->setBody($prettyPrinter->prettyPrint($stmts));
     }
     $this->struct->setMethod($m);
 }
예제 #11
0
 private function enterClassMethod(ClassMethod $node)
 {
     if ($node->isPublic()) {
         $methodName = $node->name;
         if ($this->isGetterOrSetter($methodName)) {
             $correspondingAttribute = strtolower(substr($methodName, 3));
             if (!isset($this->publicMethods[$correspondingAttribute])) {
                 $this->publicMethods[$correspondingAttribute] = array();
             }
             $this->publicMethods[$correspondingAttribute][] = $methodName;
         }
     }
 }
예제 #12
0
 static function getMethodAccessLevel(ClassMethod $level)
 {
     if ($level->isPublic()) {
         return "public";
     }
     if ($level->isPrivate()) {
         return "private";
     }
     if ($level->isProtected()) {
         return "protected";
     }
     trigger_error("Impossible");
 }
예제 #13
0
 /**
  * @param Node\Stmt\ClassMethod $node
  * @param string                $text
  *
  * @return string
  */
 public function addParams(Node\Stmt\ClassMethod $node, $text)
 {
     $docBlock = new Docblock($text);
     foreach ($node->getParams() as $param) {
         $type = $this->getFullyQualifiedParamType($param);
         if (null === $type) {
             continue;
         }
         $docBlock->appendTag(new ParamTag((string) $type . ' $' . $param->name));
     }
     return str_replace("* \n", "*\n", $docBlock->toString());
     //TODO remove once https://github.com/gossi/docblock/pull/2 is merged
 }
예제 #14
0
 public function testItContainsErrorMessageWhenSubjectNotFound()
 {
     $test = new IsRemoved();
     $func = new ClassMethod('some_method');
     $class = new Class_('the_class');
     $class->namespacedName = $class->name;
     $func->setAttribute('parent', $class);
     $old = $func;
     $new = null;
     $this->assertTrue($test->handle($old, $new));
     $this->assertTrue($test->isTriggered());
     $this->assertInstanceOf('PHPSemVer\\Constraints\\FailedConstraint', $test->lastException);
     $this->assertEquals('the_class::some_method() removed', $test->lastException->getMessage());
 }
예제 #15
0
 protected function enterPublicMethod(Stmt\ClassMethod $node)
 {
     // NS
     $methodName = $node->name;
     $currentFqcn = $this->getCurrentFqcn();
     $declaringFqcn = $this->getReflectionContext()->getDeclaringClass($currentFqcn, $methodName);
     // Vertices
     $signatureIndex = $declaringFqcn . '::' . $methodName;
     $classVertex = $this->findVertex('class', $currentFqcn);
     $signatureVertex = $this->findVertex('method', $signatureIndex);
     $implVertex = $this->findVertex('impl', $currentFqcn . '::' . $methodName);
     // if current class == declaring class, we add the edge
     if ($declaringFqcn == $currentFqcn) {
         $this->getGraph()->addEdge($classVertex, $signatureVertex);
         // C -> M
         if (!$node->isAbstract()) {
             $this->getGraph()->addEdge($signatureVertex, $implVertex);
             // M -> S
             $this->getGraph()->addEdge($implVertex, $classVertex);
             // S -> C
         }
     } else {
         if (!$node->isAbstract()) {
             $this->getGraph()->addEdge($classVertex, $implVertex);
             // C -> S
             $this->getGraph()->addEdge($implVertex, $classVertex);
             // S -> C
         }
     }
     // in any case, we link the implementation to the params
     foreach ($node->params as $idx => $param) {
         // adding edge from signature to param :
         $paramVertex = $this->findVertex('param', $signatureIndex . '/' . $idx);
         // it is possible to not find the param because the signature
         // is external to the source code :
         if (!is_null($paramVertex)) {
             if (!$node->isAbstract()) {
                 $this->getGraph()->addEdge($implVertex, $paramVertex);
                 // S -> P
             }
             if ($currentFqcn === $declaringFqcn) {
                 $this->getGraph()->addEdge($signatureVertex, $paramVertex);
                 // M -> P
                 // now the type of the param :
                 $this->typeHintParam($param, $paramVertex);
             }
         }
     }
 }
 /**
  * Fetch an array of all return statements found within this function.
  *
  * Note that return statements within smaller scopes contained (e.g. anonymous classes, closures) are not returned
  * here as they are not within the immediate scope.
  *
  * @return Node\Stmt\Return_[]
  */
 public function getReturnStatementsAst()
 {
     $visitor = new ReturnNodeVisitor();
     $traverser = new NodeTraverser();
     $traverser->addVisitor($visitor);
     $traverser->traverse($this->node->getStmts());
     return $visitor->getReturnNodes();
 }
예제 #17
0
 private function getMethodNodeSignature(Node\Stmt\ClassMethod $node)
 {
     if ($node->isPublic()) {
         $accessModifier = FunctionSignature::ACCESS_PUBLIC;
     } elseif ($node->isProtected()) {
         $accessModifier = FunctionSignature::ACCESS_PROTECTED;
     } else {
         $accessModifier = FunctionSignature::ACCESS_PRIVATE;
     }
     if ($node->isFinal()) {
         $polymorphModifier = FunctionSignature::POLYMORPH_FINAL;
     } elseif ($node->isAbstract()) {
         $polymorphModifier = FunctionSignature::POLYMORPH_ABSTRACT;
     } else {
         $polymorphModifier = null;
     }
     return FunctionSignature::method($node->byRef, $accessModifier, $polymorphModifier, $node->isStatic(), $node->name, $this->getParameterExpressions($node->params));
 }
예제 #18
0
 /**
  * @param Context $context
  * @return bool
  */
 public function compile(Context $context)
 {
     if ($this->st->getDocComment() === null) {
         return $context->notice('missing-docblock', sprintf('Missing docblock for %s() method', $this->name), $this->st);
     }
     if (count($this->ast) == 0) {
         return $context->notice('not-implemented-method', sprintf('Method %s() is not implemented', $this->name), $this->st);
     }
     if (count($this->st->params) > 0) {
         /** @var  Node\Param $parameter */
         foreach ($this->st->params as $parameter) {
             $context->addSymbol($parameter->name);
         }
     }
     foreach ($this->ast as $st) {
         $result = \PHPSA\nodeVisitorFactory($st, $context);
     }
 }
예제 #19
0
 /**
  * @param ClassMethod $methodStmt
  * @param Context $context
  * @return bool
  */
 public function pass(ClassMethod $methodStmt, Context $context)
 {
     $functionName = $methodStmt->name;
     if (!$functionName) {
         return false;
     }
     if (substr($functionName, 0, 4) !== 'test') {
         return false;
     }
     if ($methodStmt->getDocComment()) {
         $phpdoc = $this->docBlockFactory->create($methodStmt->getDocComment()->getText());
         if ($phpdoc->hasTag('test')) {
             $context->notice('test.annotation', 'Annotation @test is not needed when the method is prefixed with test.', $methodStmt);
             return true;
         }
     }
     return false;
 }
예제 #20
0
 /**
  * @param Node\Stmt\ClassMethod $node
  * @param string                $text
  *
  * @return string
  */
 public function addParams(Node\Stmt\ClassMethod $node, $text)
 {
     $docBlock = new Docblock($text);
     foreach ($node->getParams() as $param) {
         if ($param->type && $param->type instanceof Node\Name) {
             $type = $this->resolver->resolve(implode('\\', $param->type->parts), $this->context);
             $type = str_replace('\\\\', '\\', $type);
         } elseif ($param->type && is_string($param->type)) {
             $type = $param->type;
         }
         if (!isset($type)) {
             continue;
         }
         $docBlock->appendTag(new ParamTag((string) $type . ' $' . $param->name));
     }
     $string = $docBlock->toString();
     return str_replace("* \n", "*\n", $string);
     //TODO remove once https://github.com/gossi/docblock/pull/2 is merged
 }
예제 #21
0
        /**
         * @param \PhpParser\Node\Stmt\ClassMethod $node
         */
        private function processMethod(\PhpParser\Node\Stmt\ClassMethod $node) {

            /** @var $method \TheSeer\phpDox\Collector\MethodObject */
            $method = $this->unit->addMethod($node->name);
            $method->setStartLine($node->getAttribute('startLine'));
            $method->setEndLine($node->getAttribute('endLine'));
            $method->setAbstract($node->isAbstract());
            $method->setFinal($node->isFinal());
            $method->setStatic($node->isStatic());

            $visibility = 'public';
            if ($node->isPrivate()) {
                $visibility = 'private';
            } elseif ($node->isProtected()) {
                $visibility = 'protected';
            }
            $method->setVisibility($visibility);
            $docComment = $node->getDocComment();
            if ($docComment !== NULL) {
                $block = $this->dockblocParser->parse($docComment, $this->aliasMap);
                $method->setDocBlock($block);
            }
            $this->processMethodParams($method, $node->params);
            if ($node->stmts) {
                $this->processInlineComments($method, $node->stmts);
            }
        }
예제 #22
0
 protected function extractStmtClassMethod(Stmt\ClassMethod $node)
 {
     return ['Kind' => Grapher::KIND_METHOD, 'Name' => $node->name, 'Path' => $node->namespacedName->toString('/'), 'Exported' => $node->isPublic()];
 }
예제 #23
0
 /**
  * @param ClassMethod $node
  *
  * @return RefMethod
  */
 private function createMethod(ClassMethod $node)
 {
     $ref = new RefMethod();
     $ref->class = $this->class;
     $ref->name = $node->name;
     if ($node->isPrivate()) {
         $ref->visibility = Visibility::IS_PRIVATE;
     } elseif ($node->isProtected()) {
         $ref->visibility = Visibility::IS_PROTECTED;
     } elseif ($node->isPublic()) {
         $ref->visibility = Visibility::IS_PUBLIC;
     }
     $ref->isStatic = $node->isStatic();
     $ref->isAbstract = $node->isAbstract();
     $ref->isFinal = $node->isFinal();
     $ref->startLine = $node->getLine();
     $ref->docComment = $this->createDocComment($node);
     $ref->returnType = $this->getTypeName($node->getReturnType());
     foreach ($node->getParams() as $param) {
         $param = $this->createParam($param, $ref->docComment);
         $ref->params[$param->name] = $param;
     }
     return $ref;
 }
예제 #24
0
 public function pStmt_ClassMethod(Stmt\ClassMethod $node)
 {
     $firstToken = '';
     $lastToken = '';
     if (count($node->params) > 0) {
         if ($node->getAttribute('startLine') != reset($node->params)->getAttribute('startLine')) {
             $firstToken = LF . $this->indentToken;
         }
         // if the last parameters endline is 2 lines above the first statements
         // startLine, the closing bracket is in a new line (except if there is a comment)
         if ($this->getFirstLineOfMethodBody($node->stmts) - end($node->params)->getAttribute('endLine') > 1) {
             $lastToken = LF;
         }
     }
     return $this->pModifiers($node->type) . 'function ' . ($node->byRef ? '&' : '') . $node->name . '(' . $firstToken . $this->pParameterNodes($node->params) . $lastToken . ')' . (NULL !== $node->stmts ? ' {' . LF . $this->pStmts($node->stmts) . LF . '}' . LF : ';');
 }
 public function isPublic() : bool
 {
     return $this->classMethod->isPublic();
 }
 /**
  * @return int
  */
 public function getLine()
 {
     return $this->classMethodAfter->getLine();
 }
예제 #27
0
 /**
  * Ищвлекает тело метода из текущего узла
  *
  * @param Node|ClassMethod $stmt    Узел
  * @param Method[]         $methods Список методов
  *
  * @return void
  */
 private function extractMethod($stmt, array &$methods)
 {
     if (!$stmt instanceof ClassMethod) {
         return;
     }
     $skip = $this->isPublicOnly && $stmt->isPublic() === false;
     if (!$skip) {
         $methods[] = new Method(new MethodContext($this->context->namespace, $this->context->class), $stmt->name, $this->printer->prettyPrint([$stmt]));
     }
 }
 /**
  * @param Node\Stmt\ClassMethod $node
  */
 protected function parseClassMethodNode(Node\Stmt\ClassMethod $node)
 {
     $parameters = [];
     /** @var \PhpParser\Node\Param $param */
     foreach ($node->params as $param) {
         $parameters[] = ['name' => $param->name, 'type' => (string) $param->type, 'isReference' => $param->byRef, 'isVariadic' => $param->variadic, 'isOptional' => $param->default ? true : false];
     }
     $this->structuralElements[$this->currentStructuralElement->namespacedName->toString()]['methods'][] = ['name' => $node->name, 'startLine' => $node->getLine(), 'isPublic' => $node->isPublic(), 'isPrivate' => $node->isPrivate(), 'isProtected' => $node->isProtected(), 'isStatic' => $node->isStatic(), 'returnType' => $node->getReturnType(), 'parameters' => $parameters, 'docComment' => $node->getDocComment() ? $node->getDocComment()->getText() : null];
 }
 /**
  * Get the line number that this function ends on.
  *
  * @return int
  */
 public function getEndLine()
 {
     return (int) $this->node->getAttribute('endLine', -1);
 }
 /**
  * @return int
  */
 public function getLine()
 {
     return $this->classMethodBefore->getLine();
 }