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

add support of php attributes #91

Merged
merged 4 commits into from
May 24, 2024
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
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