Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

printer render attributes #77

Merged
merged 2 commits into from
Jan 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion lib/PHPCfg/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -1570,7 +1570,6 @@ private function mapAttributes(Node $expr)
return array_merge(
[
'filename' => $this->fileName,
'doccomment' => $expr->getDocComment(),
],
$expr->getAttributes()
);
Expand Down
24 changes: 23 additions & 1 deletion lib/PHPCfg/Printer.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@ abstract class Printer
/** @var \SplObjectStorage */
private $blocks;

public function __construct()
/** @var bool */
private $renderAttributes;

public function __construct(bool $renderAttributes = false)
{
$this->renderAttributes = $renderAttributes;
$this->reset();
}

Expand Down Expand Up @@ -104,13 +108,17 @@ protected function renderOperand(Operand $var)
protected function renderOp(Op $op)
{
$result = $op->getType();

if ($op instanceof Op\CallableOp) {
$func = $op->getFunc();
$result .= '<'.$func->name.'>';
}
if ($op instanceof Op\Expr\Assertion) {
$result .= '<'.$this->renderAssertion($op->assertion).'>';
}

$result .= $this->renderAttributes($op->getAttributes());

if ($op instanceof Op\Stmt\Property) {
$result .= "\n flags: " . $this->indent($this->renderFlags($op));
$result .= "\n declaredType: " . $this->indent($this->renderType($op->declaredType));
Expand Down Expand Up @@ -314,4 +322,18 @@ protected function renderFlags(Op\Stmt $stmt): string

return $result;
}

public function renderAttributes(array $attributes): string
{
$result = '';
if ($this->renderAttributes) {
foreach ($attributes as $key => $value) {
if (is_string($value) || is_numeric($value)) {
$result .= "\n attribute['".$key."']: ".$value;
}
}
}

return $result;
}
}
181 changes: 181 additions & 0 deletions test/PHPCfg/AttributesTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
<?php

declare(strict_types=1);

/**
* This file is part of PHP-CFG, a Control flow graph implementation for PHP
*
* @copyright 2015 Anthony Ferrara. All rights reserved
* @license MIT See LICENSE at the root of the project for more info
*/

namespace PHPCfg;

use PhpParser;
use PhpParser\ParserFactory;
use PHPUnit\Framework\TestCase;

class AttributesTest extends TestCase
{
public function testDefault()
{
$code = <<< EOF
<?php
function foo(\$a) {
return \$a;
}
EOF;

$expected = <<< EOF
Block#1
Stmt_Function<foo>
Terminal_Return

Function foo(): mixed
Block#1
Expr_Param
declaredType: mixed
name: LITERAL('a')
result: Var#1<\$a>
Terminal_Return
expr: Var#1<\$a>
EOF;

$parser = new Parser((new ParserFactory())->create(ParserFactory::PREFER_PHP7), null);
$traverser = new Traverser();
$traverser->addVisitor(new Visitor\Simplifier());
$printer = new Printer\Text();

try {
$script = $parser->parse($code, 'foo.php');
$traverser->traverse($script);
$result = $printer->printScript($script);
} catch (\RuntimeException $e) {
$result = $e->getMessage();
}

$this->assertEquals($this->canonicalize($expected), $this->canonicalize($result));
}

public function testAttributes()
{
$code = <<< EOF
<?php
function foo(\$a) {
return \$a;
}
EOF;

$expected = <<< EOF
Block#1
Stmt_Function<foo>
attribute['filename']: foo.php
attribute['startLine']: 2
attribute['endLine']: 4
Terminal_Return

Function foo(): mixed
Block#1
Expr_Param
attribute['filename']: foo.php
attribute['startLine']: 2
attribute['endLine']: 2
declaredType: mixed
name: LITERAL('a')
result: Var#1<\$a>
Terminal_Return
attribute['filename']: foo.php
attribute['startLine']: 3
attribute['endLine']: 3
expr: Var#1<\$a>
EOF;

$parser = new Parser((new ParserFactory())->create(ParserFactory::PREFER_PHP7), null);
$traverser = new Traverser();
$traverser->addVisitor(new Visitor\Simplifier());
$printer = new Printer\Text(true);

try {
$script = $parser->parse($code, 'foo.php');
$traverser->traverse($script);
$result = $printer->printScript($script);
} catch (\RuntimeException $e) {
$result = $e->getMessage();
}

$this->assertEquals($this->canonicalize($expected), $this->canonicalize($result));
}

public function testAdditionalAttributes()
{
$code = <<< EOF
<?php
function foo(\$a) {
return \$a;
}
EOF;

$expected = <<< EOF
Block#1
Stmt_Function<foo>
attribute['filename']: foo.php
attribute['startLine']: 2
attribute['startFilePos']: 6
attribute['endLine']: 4
attribute['endFilePos']: 40
Terminal_Return

Function foo(): mixed
Block#1
Expr_Param
attribute['filename']: foo.php
attribute['startLine']: 2
attribute['startFilePos']: 19
attribute['endLine']: 2
attribute['endFilePos']: 20
declaredType: mixed
name: LITERAL('a')
result: Var#1<\$a>
Terminal_Return
attribute['filename']: foo.php
attribute['startLine']: 3
attribute['startFilePos']: 29
attribute['endLine']: 3
attribute['endFilePos']: 38
expr: Var#1<\$a>
EOF;

$lexer = new \PhpParser\Lexer(array(
'usedAttributes' => array(
'comments', 'startLine', 'endLine', 'startFilePos', 'endFilePos'
)
));

$parser = new Parser((new ParserFactory())->create(ParserFactory::PREFER_PHP7, $lexer), null);
$traverser = new Traverser();
$traverser->addVisitor(new Visitor\Simplifier());
$printer = new Printer\Text(true);

try {
$script = $parser->parse($code, 'foo.php');
$traverser->traverse($script);
$result = $printer->printScript($script);
} catch (\RuntimeException $e) {
$result = $e->getMessage();
}

$this->assertEquals($this->canonicalize($expected), $this->canonicalize($result));
}

private function canonicalize($str)
{
// trim from both sides
$str = trim($str);

// normalize EOL to \n
$str = str_replace(["\r\n", "\r"], "\n", $str);

// trim right side of all lines
return implode("\n", array_map('rtrim', explode("\n", $str)));
}
}