Permalink
Browse files

add function parameter type completion form phpdoc

  • Loading branch information...
sters committed Nov 14, 2018
1 parent 71f7008 commit b8e3d96d405e05a3384842f4d3e39b2595adde37
Showing with 225 additions and 12 deletions.
  1. +2 −1 composer.json
  2. +47 −1 composer.lock
  3. +72 −10 src/Converter/GoLikePrettyPrinter.php
  4. +104 −0 test/Converter/ConverterControllerTest.php
@@ -17,7 +17,8 @@
}
},
"require": {
"nikic/php-parser": "^4.0"
"nikic/php-parser": "^4.0",
"phpstan/phpdoc-parser": "^0.3.0"
},
"require-dev": {
"phpunit/phpunit": "^7.0"

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
@@ -12,6 +12,12 @@
use PhpParser\Node\Scalar\MagicConst;
use PhpParser\Node\Stmt;
use PhpParser\PrettyPrinter\Standard;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\ConstExprParser;
use PHPStan\PhpDocParser\Parser\PhpDocParser;
use PHPStan\PhpDocParser\Parser\TokenIterator;
use PHPStan\PhpDocParser\Parser\TypeParser;
class GoLikePrettyPrinter extends Standard
{
@@ -27,6 +33,24 @@ class GoLikePrettyPrinter extends Standard
/** @var Node */
private $lastNode = null;
/** @var Lexer */
private $phpDocLexer = null;
/** @var PhpDocParser */
private $phpDocParser = null;
/**
* GoLikePrettyPrinter constructor.
* @param array $options
*/
public function __construct(array $options = [])
{
parent::__construct($options);
$this->phpDocLexer = new Lexer();
$this->phpDocParser = new PhpDocParser(new TypeParser(), new ConstExprParser());
}
/**
* @param string $key
* @param string $code
@@ -613,20 +637,12 @@ protected function pStmt_ClassConst(Stmt\ClassConst $node)
protected function pStmt_ClassMethod(Stmt\ClassMethod $node)
{
return 'func ' . ($node->byRef ? '&' : '') . $node->name
. '(' . $this->pCommaSeparated($node->params) . ')'
. (null !== $node->returnType ? ' ' . $this->p($node->returnType) : '')
. (null !== $node->stmts
? '{' . $this->pStmts($node->stmts) . $this->nl . '}'
: ';');
return $this->pFunctionLike($node);
}
protected function pStmt_Function(Stmt\Function_ $node)
{
return 'func ' . ($node->byRef ? '&' : '') . $node->name
. '(' . $this->pCommaSeparated($node->params) . ')'
. (null !== $node->returnType ? ' : ' . $this->p($node->returnType) : '')
. '{' . $this->pStmts($node->stmts) . $this->nl . '}';
return $this->pFunctionLike($node);
}
protected function pStmt_Const(Stmt\Const_ $node)
@@ -767,4 +783,50 @@ protected function pSingleQuotedString(string $string)
{
return '"' . addcslashes($string, '"\\') . '"';
}
/**
* @param string $input
* @return PhpDocNode
*/
private function parseDocComment(string $input): PhpDocNode
{
$tokens = new TokenIterator($this->phpDocLexer->tokenize($input));
return $this->phpDocParser->parse($tokens);
}
/**
* @param Stmt\Function_|Stmt\ClassMethod $node
* @return string
*/
private function pFunctionLike($node): string
{
$comment = $this->parseDocComment($node->getDocComment() ?? '/** */');
$paramsComment = $comment->getParamTagValues();
$params = [];
foreach ($node->params as $paramNode) {
if (null === $paramNode) {
$params[] = '';
continue;
}
$typeString = null;
foreach($paramsComment as $paramComment) {
if ($paramComment->parameterName === ('$' . $paramNode->var->name)) {
$typeString = $paramComment->type;
break;
}
}
$params[] = $this->p($paramNode) . ($typeString != null ? ' ' . $typeString : '');
}
$paramsString = implode(', ', $params);
return 'func ' . ($node->byRef ? '&' : '') . $node->name
. '(' . $paramsString . ')'
. (null !== $node->returnType ? ' : ' . $this->p($node->returnType) : '')
. (null !== $node->stmts
? ' {' . $this->pStmts($node->stmts) . $this->nl . '}'
: ' {}');
}
}
@@ -4,7 +4,9 @@
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Expression;
use PhpParser\ParserFactory;
use PhpToGo\Converter\ConverterController;
@@ -249,4 +251,106 @@ public function providerMethodCall(): array
],
];
}
/**
* @param string $code
* @param string $expectCode
*
* @dataProvider providerFunctionLike
*/
public function testFunctionLike($code, $expectCode)
{
$ast = $this->getSimpleAst($code)[0];
if (!($ast instanceof Stmt)) {
$this->fail('Cannot convert to statement: ' . $code);
}
if (!($ast instanceof FunctionLike)) {
$this->fail('Cannot convert to FunctionLike: ' . $code);
}
$result = $this->converter->convert("<?php\n" . $code . ";\n");
$this->assertEquals($expectCode, $result);
}
/**
* @return array
*/
public function providerFunctionLike(): array
{
return [
'simple function' => [
$this->m(
'function dummy() {',
self::INDENT . 'echo "ok";',
'}'
),
$this->m(
'func dummy() {',
self::INDENT . 'fmt.Print("ok")',
'}'
),
],
'include param' => [
$this->m(
'function dummy($hoge) {',
self::INDENT . 'echo $hoge;',
'}'
),
$this->m(
'func dummy(hoge) {',
self::INDENT . 'fmt.Print(hoge)',
'}'
),
],
'include param with phpdoc' => [
$this->m(
'/**',
' * @param string $hoge',
' */',
'function dummy($hoge) {',
self::INDENT . 'echo $hoge;',
'}'
),
$this->m(
'/**',
' * @param string $hoge',
' */',
'func dummy(hoge string) {',
self::INDENT . 'fmt.Print(hoge)',
'}'
),
],
'include param with phpdoc but no match' => [
$this->m(
'/**',
' * @param string $foo',
' */',
'function dummy($hoge) {',
self::INDENT . 'echo $hoge;',
'}'
),
$this->m(
'/**',
' * @param string $foo',
' */',
'func dummy(hoge) {',
self::INDENT . 'fmt.Print(hoge)',
'}'
),
],
'include param with type' => [
$this->m(
'function dummy(int $hoge) {',
self::INDENT . 'echo $hoge;',
'}'
),
$this->m(
'func dummy(hoge int) {',
self::INDENT . 'fmt.Print(hoge)',
'}'
),
],
];
}
}

0 comments on commit b8e3d96

Please sign in to comment.