Skip to content

Commit

Permalink
Merge pull request #91 from eric-therond/addphpattributes
Browse files Browse the repository at this point in the history
add support of php attributes
  • Loading branch information
ircmaxell authored May 24, 2024
2 parents b96ffc5 + 919ccb1 commit 4fd3db9
Show file tree
Hide file tree
Showing 15 changed files with 397 additions and 15 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
composer.lock
test.php
vendor/
.idea/
.idea/
.phpunit.result.cache
29 changes: 29 additions & 0 deletions lib/PHPCfg/Op/Attributes/Attribute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?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\Op\Attributes;

use PHPCfg\Op;
use PhpCfg\Operand;

class Attribute extends Op
{
public Operand $name;

public array $args;

public function __construct(Operand $name, array $args, array $attributes = [])
{
parent::__construct($attributes);
$this->name = $this->addReadRef($name);
$this->args = $args;
}
}
25 changes: 25 additions & 0 deletions lib/PHPCfg/Op/Attributes/AttributeGroup.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?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\Op\Attributes;

use PHPCfg\Op;

class AttributeGroup extends Op
{
public array $attrs;

public function __construct(array $attrs, array $attributes = [])
{
parent::__construct($attributes);
$this->attrs = $attrs;
}
}
4 changes: 4 additions & 0 deletions lib/PHPCfg/Op/Expr/Param.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class Param extends Expr
public bool $byRef;

public bool $variadic;

public array $attrGroups;

public ?Operand $defaultVar = null;

Expand All @@ -39,6 +41,7 @@ public function __construct(
Op\Type $type,
bool $byRef,
bool $variadic,
array $attrGroups,
?Operand $defaultVar = null,
?Block $defaultBlock = null,
array $attributes = []
Expand All @@ -49,6 +52,7 @@ public function __construct(
$this->declaredType = $type;
$this->byRef = $byRef;
$this->variadic = $variadic;
$this->attrGroups = $attrGroups;
if (!is_null($defaultVar)) {
$this->defaultVar = $this->addReadRef($defaultVar);
}
Expand Down
4 changes: 2 additions & 2 deletions lib/PHPCfg/Op/Stmt/ClassMethod.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ class ClassMethod extends Function_

public bool $abstract;

public function __construct(Func $func, int $visiblity, bool $static, bool $final, bool $abstract, array $attributes = [])
public function __construct(Func $func, int $visiblity, bool $static, bool $final, bool $abstract, array $attrGroups, array $attributes = [])
{
parent::__construct($func, $attributes);
parent::__construct($func, $attrGroups, $attributes);
$this->visibility = $visiblity;
$this->static = $static;
$this->final = $final;
Expand Down
5 changes: 4 additions & 1 deletion lib/PHPCfg/Op/Stmt/Class_.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@ class Class_ extends ClassLike

public array $implements;

public function __construct(Operand $name, int $flags, ?Operand $extends, array $implements, Block $stmts, array $attributes = [])
public array $attrGroups;

public function __construct(Operand $name, int $flags, ?Operand $extends, array $implements, Block $stmts, array $attrGroups, array $attributes = [])
{
parent::__construct($name, $stmts, $attributes);
$this->flags = $flags;
$this->extends = $extends;
$this->implements = $implements;
$this->attrGroups = $attrGroups;
}

public function getVariableNames(): array
Expand Down
5 changes: 4 additions & 1 deletion lib/PHPCfg/Op/Stmt/Function_.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ class Function_ extends Stmt implements CallableOp
{
public Func $func;

public function __construct(Func $func, array $attributes = [])
public array $attrGroups;

public function __construct(Func $func, array $attrGroups, array $attributes = [])
{
parent::__construct($attributes);
$this->func = $func;
$this->attrGroups = $attrGroups;
}

public function getFunc(): Func
Expand Down
5 changes: 4 additions & 1 deletion lib/PHPCfg/Op/Stmt/Property.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,23 @@ class Property extends Stmt
public bool $static;

public bool $readonly;

public array $attrGroups;

public ?Operand $defaultVar = null;

public ?Block $defaultBlock = null;

public Op\Type $declaredType ;

public function __construct(Operand $name, int $visiblity, bool $static, bool $readonly, Op\Type $declaredType = null, Operand $defaultVar = null, Block $defaultBlock = null, array $attributes = [])
public function __construct(Operand $name, int $visiblity, bool $static, bool $readonly, array $attrGroups, Op\Type $declaredType = null, Operand $defaultVar = null, Block $defaultBlock = null, array $attributes = [])
{
parent::__construct($attributes);
$this->name = $this->addReadRef($name);
$this->visibility = $visiblity;
$this->static = $static;
$this->readonly = $readonly;
$this->attrGroups = $attrGroups;
$this->declaredType = $declaredType;
if (!is_null($defaultVar)) {
$this->defaultVar = $this->addReadRef($defaultVar);
Expand Down
33 changes: 32 additions & 1 deletion lib/PHPCfg/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,16 @@ protected function parseFunc(Func $func, array $params, array $stmts)

$start = $func->cfg;

$tmp = $this->block;
$this->block = $start;

$func->params = $this->parseParameterList($func, $params);
foreach ($func->params as $param) {
$this->writeVariableName($param->name->value, $param->result, $start);
$start->children[] = $param;
}

$this->block = $tmp;

$end = $this->parseNodes($stmts, $start);

Expand Down Expand Up @@ -163,6 +169,7 @@ protected function parseNode(Node $node)

return;
}

$type = $node->getType();
if (method_exists($this, 'parse'.$type)) {
$this->{'parse'.$type}($node);
Expand Down Expand Up @@ -226,6 +233,7 @@ protected function parseStmt_Class(Stmt\Class_ $node)
$this->parseExprNode($node->extends),
$this->parseExprList($node->implements),
$this->parseNodes($node->stmts, new Block()),
$this->parseAttributeGroups($node->attrGroups),
$this->mapAttributes($node)
);
$this->currentClass = $old;
Expand Down Expand Up @@ -282,6 +290,7 @@ protected function parseStmt_ClassMethod(Stmt\ClassMethod $node)
(bool) $static,
(bool) $final,
(bool) $abstract,
$this->parseAttributeGroups($node->attrGroups),
$this->mapAttributes($node)
);
$func->callableOp = $class_method;
Expand Down Expand Up @@ -416,7 +425,7 @@ protected function parseStmt_Function(Stmt\Function_ $node)
null,
);
$this->parseFunc($func, $node->params, $node->stmts, null);
$this->block->children[] = $function = new Op\Stmt\Function_($func, $this->mapAttributes($node));
$this->block->children[] = $function = new Op\Stmt\Function_($func, $this->parseAttributeGroups($node->attrGroups), $this->mapAttributes($node));
$func->callableOp = $function;
}

Expand Down Expand Up @@ -566,11 +575,13 @@ protected function parseStmt_Property(Stmt\Property $node)
$defaultVar = null;
$defaultBlock = null;
}

$this->block->children[] = new Op\Stmt\Property(
$this->parseExprNode($prop->name),
$visibility,
(bool) $static,
(bool) $readonly,
$this->parseAttributeGroups($node->attrGroups),
$this->parseTypeNode($node->type),
$defaultVar,
$defaultBlock,
Expand Down Expand Up @@ -928,6 +939,25 @@ protected function parseArg(Node\Arg $expr)
return $this->readVariable($this->parseExprNode($expr->value));
}

protected function parseAttribute(Node\Attribute $attr)
{
$args = array_map([$this, 'parseArg'], $attr->args);

return new Op\Attributes\Attribute($this->readVariable($this->parseExprNode($attr->name)), $args, $this->mapAttributes($attr));
}

protected function parseAttributeGroup(Node\AttributeGroup $attrGroup)
{
$attrs = array_map([$this, 'parseAttribute'], $attrGroup->attrs);

return new Op\Attributes\AttributeGroup($attrs, $this->mapAttributes($attrGroup));
}

protected function parseAttributeGroups(array $attrGroups)
{
return array_map([$this, 'parseAttributeGroup'], $attrGroups);
}

protected function parseExpr_Array(Expr\Array_ $expr)
{
$keys = [];
Expand Down Expand Up @@ -1547,6 +1577,7 @@ private function parseParameterList(Func $func, array $params)
$this->parseTypeNode($param->type),
$param->byRef,
$param->variadic,
$this->parseAttributeGroups($param->attrGroups),
$defaultVar,
$defaultBlock,
$this->mapAttributes($param)
Expand Down
32 changes: 27 additions & 5 deletions lib/PHPCfg/Printer.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,12 @@ protected function renderOp(Op $op)

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

if ($op instanceof Op\Stmt\Function_ || $op instanceof Op\Stmt\Class_) {
$result .= $this->renderAttrGroups($op->attrGroups);
}

if ($op instanceof Op\Stmt\Property) {
$result .= $this->renderAttrGroups($op->attrGroups);
$result .= "\n flags: " . $this->indent($this->renderFlags($op));
$result .= "\n declaredType: " . $this->indent($this->renderType($op->declaredType));
}
Expand Down Expand Up @@ -163,9 +168,11 @@ protected function renderOp(Op $op)
}
}
if ($op instanceof Op\Stmt\ClassMethod) {
$result .= $this->renderAttrGroups($op->attrGroups);
$result .= "\n flags: " . $this->indent($this->renderFlags($op));
}
if ($op instanceof Op\Expr\Param) {
$result .= $this->renderAttrGroups($op->attrGroups);
$result .= "\n declaredType: " . $this->indent($this->renderType($op->declaredType));
}
if ($op instanceof Op\Expr\Include_) {
Expand Down Expand Up @@ -266,11 +273,6 @@ protected function render(Func $func)
while ($this->blockQueue->count() > 0) {
$block = $this->blockQueue->dequeue();
$ops = [];
if ($block === $func->cfg) {
foreach ($func->params as $param) {
$renderedOps[$param] = $ops[] = $this->renderOp($param);
}
}
foreach ($block->phi as $phi) {
$result = $this->indent($this->renderOperand($phi->result).' = Phi(');
$result .= implode(', ', array_map([$this, 'renderOperand'], $phi->vars));
Expand Down Expand Up @@ -394,4 +396,24 @@ public function renderAttributes(array $attributes): string

return $result;
}

public function renderAttrGroups(array $attrGroups): string
{
$result = '';

foreach($attrGroups as $indexGroup => $attrGroup) {
$result .= "\n attrGroup[$indexGroup]: ";
$result .= $this->indent($this->renderAttributes($attrGroup->getAttributes()));
foreach($attrGroup->attrs as $indexAttr => $attr) {
$result .= "\n attr[$indexAttr]: ";
$result .= $this->indent($this->renderAttributes($attr->getAttributes()), 2);
$result .= "\n name: ".$this->renderOperand($attr->name);
foreach($attr->args as $indexArg => $arg) {
$result .= "\n args[$indexArg]: ".$this->renderOperand($arg);
}
}
}

return $result;
}
}
35 changes: 34 additions & 1 deletion test/PHPCfg/AttributesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ public function testAttributes()
function foo(\$a) {
return \$a;
}
#[Attr]
function foowithattribute(\$a) {
return \$a;
}
EOF;

$expected = <<< EOF
Expand All @@ -72,8 +77,21 @@ function foo(\$a) {
attribute['filename']: foo.php
attribute['startLine']: 2
attribute['endLine']: 4
Stmt_Function<'foowithattribute'>
attribute['filename']: foo.php
attribute['startLine']: 6
attribute['endLine']: 9
attrGroup[0]:
attribute['filename']: foo.php
attribute['startLine']: 6
attribute['endLine']: 6
attr[0]:
attribute['filename']: foo.php
attribute['startLine']: 6
attribute['endLine']: 6
name: LITERAL('Attr')
Terminal_Return
Function 'foo': mixed
Block#1
Expr_Param
Expand All @@ -88,6 +106,21 @@ function foo(\$a) {
attribute['startLine']: 3
attribute['endLine']: 3
expr: Var#1<\$a>
Function 'foowithattribute': mixed
Block#1
Expr_Param
attribute['filename']: foo.php
attribute['startLine']: 7
attribute['endLine']: 7
declaredType: mixed
name: LITERAL('a')
result: Var#1<\$a>
Terminal_Return
attribute['filename']: foo.php
attribute['startLine']: 8
attribute['endLine']: 8
expr: Var#1<\$a>
EOF;

$parser = new Parser((new ParserFactory())->create(ParserFactory::PREFER_PHP7), null);
Expand Down
Loading

0 comments on commit 4fd3db9

Please sign in to comment.