Skip to content

Commit

Permalink
add support of php attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-therond committed Jan 11, 2024
1 parent b96ffc5 commit 952634c
Show file tree
Hide file tree
Showing 15 changed files with 456 additions and 24 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
34 changes: 34 additions & 0 deletions lib/PHPCfg/Op/Expr/Attribute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?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\Expr;

use PHPCfg\Op\Expr;
use PhpCfg\Operand;

class Attribute extends Expr
{
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;
}

public function getVariableNames(): array
{
return ['name', 'args', 'result'];
}
}
30 changes: 30 additions & 0 deletions lib/PHPCfg/Op/Expr/AttributeGroup.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?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\Expr;

use PHPCfg\Op\Expr;

class AttributeGroup extends Expr
{
public array $attrs;

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

public function getVariableNames(): array
{
return ['attrs', 'result'];
}
}
6 changes: 5 additions & 1 deletion 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 All @@ -57,7 +61,7 @@ public function __construct(

public function getVariableNames(): array
{
return ['name', 'defaultVar', 'result'];
return ['name', 'attrGroups', 'defaultVar', 'result'];
}

public function getSubBlocks(): array
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
7 changes: 5 additions & 2 deletions lib/PHPCfg/Op/Stmt/Class_.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,19 @@ 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
{
return ['name', 'extends', 'implements'];
return ['name', 'attrGroups', 'extends', 'implements'];
}
}
10 changes: 9 additions & 1 deletion lib/PHPCfg/Op/Stmt/Function_.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,22 @@ 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
{
return $this->func;
}

public function getVariableNames(): array
{
return ['attrGroups'];
}
}
7 changes: 5 additions & 2 deletions 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 Expand Up @@ -74,7 +77,7 @@ public function isReadonly() : bool

public function getVariableNames(): array
{
return ['name', 'defaultVar'];
return ['name', 'attrGroups', 'defaultVar'];
}

public function getSubBlocks(): array
Expand Down
26 changes: 25 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 @@ -226,6 +232,7 @@ protected function parseStmt_Class(Stmt\Class_ $node)
$this->parseExprNode($node->extends),
$this->parseExprList($node->implements),
$this->parseNodes($node->stmts, new Block()),
$this->parseExprList($node->attrGroups),
$this->mapAttributes($node)
);
$this->currentClass = $old;
Expand Down Expand Up @@ -282,6 +289,7 @@ protected function parseStmt_ClassMethod(Stmt\ClassMethod $node)
(bool) $static,
(bool) $final,
(bool) $abstract,
$this->parseExprList($node->attrGroups),
$this->mapAttributes($node)
);
$func->callableOp = $class_method;
Expand Down Expand Up @@ -416,7 +424,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->parseExprList($node->attrGroups), $this->mapAttributes($node));
$func->callableOp = $function;
}

Expand Down Expand Up @@ -571,6 +579,7 @@ protected function parseStmt_Property(Stmt\Property $node)
$visibility,
(bool) $static,
(bool) $readonly,
$this->parseExprList($node->attrGroups),
$this->parseTypeNode($node->type),
$defaultVar,
$defaultBlock,
Expand Down Expand Up @@ -928,6 +937,20 @@ 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\Expr\Attribute($this->readVariable($this->parseExprNode($attr->name)), $args, $this->mapAttributes($attr));
}

protected function parseAttributeGroup(Node\AttributeGroup $attrGroup)
{
$attrs = $this->parseExprList($attrGroup->attrs);

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

protected function parseExpr_Array(Expr\Array_ $expr)
{
$keys = [];
Expand Down Expand Up @@ -1547,6 +1570,7 @@ private function parseParameterList(Func $func, array $params)
$this->parseTypeNode($param->type),
$param->byRef,
$param->variadic,
$this->parseExprList($param->attrGroups),
$defaultVar,
$defaultBlock,
$this->mapAttributes($param)
Expand Down
5 changes: 0 additions & 5 deletions lib/PHPCfg/Printer.php
Original file line number Diff line number Diff line change
Expand Up @@ -266,11 +266,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
51 changes: 44 additions & 7 deletions 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,25 @@ function foo(\$a) {
attribute['filename']: foo.php
attribute['startLine']: 2
attribute['endLine']: 4
Expr_Attribute
attribute['filename']: foo.php
attribute['startLine']: 6
attribute['endLine']: 6
name: LITERAL('Attr')
result: Var#1
Expr_AttributeGroup
attribute['filename']: foo.php
attribute['startLine']: 6
attribute['endLine']: 6
attrs[0]: Var#1
result: Var#2
Stmt_Function<'foowithattribute'>
attribute['filename']: foo.php
attribute['startLine']: 6
attribute['endLine']: 9
attrGroups[0]: Var#2
Terminal_Return
Function 'foo': mixed
Block#1
Expr_Param
Expand All @@ -88,6 +110,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 Expand Up @@ -120,28 +157,28 @@ function foo(\$a) {
Stmt_Function<'foo'>
attribute['filename']: foo.php
attribute['startLine']: 2
attribute['startFilePos']: 6
attribute['startFilePos']: 7
attribute['endLine']: 4
attribute['endFilePos']: 40
attribute['endFilePos']: 43
Terminal_Return
Function 'foo': mixed
Block#1
Expr_Param
attribute['filename']: foo.php
attribute['startLine']: 2
attribute['startFilePos']: 19
attribute['startFilePos']: 20
attribute['endLine']: 2
attribute['endFilePos']: 20
attribute['endFilePos']: 21
declaredType: mixed
name: LITERAL('a')
result: Var#1<\$a>
Terminal_Return
attribute['filename']: foo.php
attribute['startLine']: 3
attribute['startFilePos']: 29
attribute['startFilePos']: 31
attribute['endLine']: 3
attribute['endFilePos']: 38
attribute['endFilePos']: 40
expr: Var#1<\$a>
EOF;

Expand Down
Loading

0 comments on commit 952634c

Please sign in to comment.