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

Updated to nikic/PHP-Parser 4.x #410

Merged
merged 3 commits into from
May 8, 2018
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,12 @@ jobs:
- travis_retry composer require --dev --prefer-dist --prefer-stable doctrine/coding-standard:^4.0.0
script: vendor/bin/phpcs

- stage: Static Analysis
php: 7.1
env: DEPENDENCIES=""
before_script:
- travis_retry composer require --dev --prefer-dist --prefer-stable phpstan/phpstan:^0.9.2
script: vendor/bin/phpstan analyse -l 5 -c phpstan.neon src
#- stage: Static Analysis
# php: 7.1
# env: DEPENDENCIES=""
# before_script:
# - travis_retry composer require --dev --prefer-dist --prefer-stable phpstan/phpstan:^0.9.2
# script: vendor/bin/phpstan analyse -l 5 -c phpstan.neon src
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose it is impossible to analyse this codebase due to autoloading reflection?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly.


- stage: Run benchmarks
php: 7.1
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"license": "MIT",
"require": {
"php": ">=7.1.0,<7.3.0",
"nikic/php-parser": "^3.1.1",
"nikic/php-parser": "^4.0.0",
"phpdocumentor/reflection-docblock": "^4.1.1",
"phpdocumentor/type-resolver": "^0.4.0",
"roave/signature": "^1.0"
Expand Down
220 changes: 20 additions & 200 deletions src/NodeCompiler/CompileNodeToValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@

namespace Roave\BetterReflection\NodeCompiler;

use PhpParser\ConstExprEvaluator;
use PhpParser\Node;
use ReflectionFunction;
use Roave\BetterReflection\NodeCompiler\Exception\UnableToCompileNode;
use Roave\BetterReflection\Reflection\ReflectionClass;
use Roave\BetterReflection\Reflector\Exception\IdentifierNotFound;
use Roave\BetterReflection\Util\FileHelper;
use function array_combine;
use function array_map;
use function constant;
use function defined;
use function dirname;
Expand All @@ -22,9 +19,6 @@

class CompileNodeToValue
{
/** @var callable[]|null indexed by supported expression node class name */
private static $nodeEvaluators;

/**
* Compile an expression from a node into a value.
*
Expand All @@ -36,63 +30,31 @@ class CompileNodeToValue
*/
public function __invoke(Node $node, CompilerContext $context)
{
if ($node instanceof Node\Scalar\String_
|| $node instanceof Node\Scalar\DNumber
|| $node instanceof Node\Scalar\LNumber) {
return $node->value;
}

// common edge case - negative numbers
if ($node instanceof Node\Expr\UnaryMinus) {
return $this($node->expr, $context) * -1;
}

if ($node instanceof Node\Expr\Array_) {
return $this->compileArray($node, $context);
}

if ($node instanceof Node\Expr\ConstFetch) {
return $this->compileConstFetch($node);
}

if ($node instanceof Node\Expr\ClassConstFetch) {
return $this->compileClassConstFetch($node, $context);
}

if ($node instanceof Node\Expr\BinaryOp) {
return $this->compileBinaryOperator($node, $context);
}

if ($node instanceof Node\Scalar\MagicConst\Dir) {
return $this->compileDirConstant($context);
if ($node instanceof Node\Stmt\Expression) {
return $this($node->expr, $context);
}

if ($node instanceof Node\Scalar\MagicConst\Class_) {
return $this->compileClassConstant($context);
}
$constExprEvaluator = new ConstExprEvaluator(function (Node\Expr $node) use ($context) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the evaluator instance be preserved?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because it needs the fallback evaluator with the right context :( I tried to implemented it without the fallback evaluator and call other evaluations in catch but it doesn't work. The test CompileNodeToValueTest::testClassConstantResolutionWithAnotherClassConstant was failing because the test is combination of multiplication (supported by PHP-Parser itself) and class constants (supported by BR).

if ($node instanceof Node\Expr\ConstFetch) {
return $this->compileConstFetch($node);
}

throw new Exception\UnableToCompileNode('Unable to compile expression: ' . get_class($node));
}
if ($node instanceof Node\Expr\ClassConstFetch) {
return $this->compileClassConstFetch($node, $context);
}

/**
* Compile arrays
*
* @return mixed[]
*/
private function compileArray(Node\Expr\Array_ $arrayNode, CompilerContext $context) : array
{
$compiledArray = [];
foreach ($arrayNode->items as $arrayItem) {
$compiledValue = $this($arrayItem->value, $context);
if ($node instanceof Node\Scalar\MagicConst\Dir) {
return $this->compileDirConstant($context);
}

if ($arrayItem->key === null) {
$compiledArray[] = $compiledValue;
continue;
if ($node instanceof Node\Scalar\MagicConst\Class_) {
return $this->compileClassConstant($context);
}

$compiledArray[$this($arrayItem->key, $context)] = $compiledValue;
}
return $compiledArray;
throw new Exception\UnableToCompileNode('Unable to compile expression: ' . get_class($node));
});

return $constExprEvaluator->evaluateDirectly($node);
}

/**
Expand Down Expand Up @@ -131,7 +93,7 @@ private function compileConstFetch(Node\Expr\ConstFetch $constNode)
private function compileClassConstFetch(Node\Expr\ClassConstFetch $node, CompilerContext $context)
{
/** @var string $nodeName */
$nodeName = $node->name;
$nodeName = $node->name->name;
$className = $node->class->toString();

if ($nodeName === 'class') {
Expand All @@ -158,30 +120,6 @@ private function compileClassConstFetch(Node\Expr\ClassConstFetch $node, Compile
);
}

/**
* Compile a binary operator node
*
*
* @return mixed
*
* @throws UnableToCompileNode
*/
private function compileBinaryOperator(Node\Expr\BinaryOp $node, CompilerContext $context)
{
$evaluators = self::loadEvaluators();
$nodeClass = get_class($node);

if (! isset($evaluators[$nodeClass])) {
throw new Exception\UnableToCompileNode(sprintf(
'Unable to compile binary operator: %s',
$nodeClass
));
}

// Welcome to method overloading implemented PHP-style. Yay?
return $evaluators[$nodeClass]($node, $context, $this);
}

/**
* Compile a __DIR__ node
*/
Expand All @@ -208,122 +146,4 @@ private function getConstantDeclaringClass(string $constantName, ReflectionClass

return $parentClass ? $this->getConstantDeclaringClass($constantName, $parentClass) : null;
}

/**
* @return callable[] indexed by node class name
*/
private static function loadEvaluators() : array
{
if (self::$nodeEvaluators) {
return self::$nodeEvaluators;
}

$evaluators = self::makeEvaluators();

return self::$nodeEvaluators = array_combine(
array_map(function (callable $nodeEvaluator) : string {
/** @noinspection ExceptionsAnnotatingAndHandlingInspection */
/** @noinspection NullPointerExceptionInspection */
return (new ReflectionFunction($nodeEvaluator))->getParameters()[0]->getType()->getName();
}, $evaluators),
$evaluators
);
}

/**
* @return callable[]
*/
private static function makeEvaluators() : array
{
return [
function (Node\Expr\BinaryOp\Plus $node, CompilerContext $context, self $next) {
return $next($node->left, $context) + $next($node->right, $context);
},
function (Node\Expr\BinaryOp\Mul $node, CompilerContext $context, self $next) {
return $next($node->left, $context) * $next($node->right, $context);
},
function (Node\Expr\BinaryOp\Minus $node, CompilerContext $context, self $next) {
return $next($node->left, $context) - $next($node->right, $context);
},
function (Node\Expr\BinaryOp\Div $node, CompilerContext $context, self $next) {
return $next($node->left, $context) / $next($node->right, $context);
},
function (Node\Expr\BinaryOp\Concat $node, CompilerContext $context, self $next) {
return $next($node->left, $context) . $next($node->right, $context);
},
function (Node\Expr\BinaryOp\BooleanAnd $node, CompilerContext $context, self $next) {
return $next($node->left, $context) && $next($node->right, $context);
},
function (Node\Expr\BinaryOp\BooleanOr $node, CompilerContext $context, self $next) {
return $next($node->left, $context) || $next($node->right, $context);
},
function (Node\Expr\BinaryOp\BitwiseAnd $node, CompilerContext $context, self $next) {
return $next($node->left, $context) & $next($node->right, $context);
},
function (Node\Expr\BinaryOp\BitwiseOr $node, CompilerContext $context, self $next) {
return $next($node->left, $context) | $next($node->right, $context);
},
function (Node\Expr\BinaryOp\BitwiseXor $node, CompilerContext $context, self $next) {
return $next($node->left, $context) ^ $next($node->right, $context);
},
function (Node\Expr\BinaryOp\Equal $node, CompilerContext $context, self $next) {
/** @noinspection TypeUnsafeComparisonInspection */
// phpcs:disable SlevomatCodingStandard.ControlStructures.DisallowEqualOperators
return $next($node->left, $context) == $next($node->right, $context);
// phpcs:enable
},
function (Node\Expr\BinaryOp\Greater $node, CompilerContext $context, self $next) {
return $next($node->left, $context) > $next($node->right, $context);
},
function (Node\Expr\BinaryOp\GreaterOrEqual $node, CompilerContext $context, self $next) {
return $next($node->left, $context) >= $next($node->right, $context);
},
function (Node\Expr\BinaryOp\Identical $node, CompilerContext $context, self $next) {
return $next($node->left, $context) === $next($node->right, $context);
},
function (Node\Expr\BinaryOp\LogicalAnd $node, CompilerContext $context, self $next) {
// phpcs:disable Squiz.Operators.ValidLogicalOperators.NotAllowed
return $next($node->left, $context) and $next($node->right, $context);
// phpcs:enable
},
function (Node\Expr\BinaryOp\LogicalOr $node, CompilerContext $context, self $next) {
// phpcs:disable Squiz.Operators.ValidLogicalOperators.NotAllowed
return $next($node->left, $context) or $next($node->right, $context);
// phpcs:enable
},
function (Node\Expr\BinaryOp\LogicalXor $node, CompilerContext $context, self $next) {
return $next($node->left, $context) xor $next($node->right, $context);
},
function (Node\Expr\BinaryOp\Mod $node, CompilerContext $context, self $next) {
return $next($node->left, $context) % $next($node->right, $context);
},
function (Node\Expr\BinaryOp\NotEqual $node, CompilerContext $context, self $next) {
/** @noinspection TypeUnsafeComparisonInspection */
// phpcs:disable SlevomatCodingStandard.ControlStructures.DisallowEqualOperators
return $next($node->left, $context) != $next($node->right, $context);
// phpcs:enable
},
function (Node\Expr\BinaryOp\NotIdentical $node, CompilerContext $context, self $next) {
return $next($node->left, $context) !== $next($node->right, $context);
},
function (Node\Expr\BinaryOp\Pow $node, CompilerContext $context, self $next) {
return $next($node->left, $context) ** $next($node->right, $context);
},
function (Node\Expr\BinaryOp\ShiftLeft $node, CompilerContext $context, self $next) {
return $next($node->left, $context) << $next($node->right, $context);
},
function (Node\Expr\BinaryOp\ShiftRight $node, CompilerContext $context, self $next) {
return $next($node->left, $context) >> $next($node->right, $context);
},
function (Node\Expr\BinaryOp\Smaller $node, CompilerContext $context, self $next) {
return $next($node->left, $context) < $next($node->right, $context);
},
function (Node\Expr\BinaryOp\SmallerOrEqual $node, CompilerContext $context, self $next) {
return $next($node->left, $context) <= $next($node->right, $context);
},
function (Node\Expr\BinaryOp\Spaceship $node, CompilerContext $context, self $next) {
return $next($node->left, $context) <=> $next($node->right, $context);
},
];
}
}
12 changes: 6 additions & 6 deletions src/Reflection/ReflectionClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ public static function createFromNode(
public function getShortName() : string
{
if (! $this->isAnonymous()) {
return $this->node->name;
return $this->node->name->name;
}

$fileName = $this->getFileName();
Expand Down Expand Up @@ -745,15 +745,15 @@ public function getLocatedSource() : LocatedSource
*/
public function getStartLine() : int
{
return (int) $this->node->getAttribute('startLine', -1);
return $this->node->getStartLine();
}

/**
* Get the line number that this class ends on.
*/
public function getEndLine() : int
{
return (int) $this->node->getAttribute('endLine', -1);
return $this->node->getEndLine();
}

public function getStartColumn() : int
Expand Down Expand Up @@ -973,7 +973,7 @@ public function getTraitAliases() : array
continue;
}

$resolvedAliases[$adaptation->newName] = sprintf(
$resolvedAliases[$adaptation->newName->name] = sprintf(
'%s::%s',
$usedTrait->toString(),
$adaptation->method
Expand Down Expand Up @@ -1321,7 +1321,7 @@ public function removeMethod(string $methodName) : bool
{
$lowerName = strtolower($methodName);
foreach ($this->node->stmts as $key => $stmt) {
if ($stmt instanceof ClassMethod && $lowerName === strtolower($stmt->name)) {
if ($stmt instanceof ClassMethod && $lowerName === $stmt->name->toLowerString()) {
unset($this->node->stmts[$key], $this->cachedMethods);
return true;
}
Expand Down Expand Up @@ -1383,7 +1383,7 @@ public function removeProperty(string $propertyName) : bool
}

$propertyNames = array_map(function (Node\Stmt\PropertyProperty $propertyProperty) : string {
return strtolower($propertyProperty->name);
return $propertyProperty->name->toLowerString();
}, $stmt->props);

if (in_array($lowerName, $propertyNames, true)) {
Expand Down
6 changes: 3 additions & 3 deletions src/Reflection/ReflectionClassConstant.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public static function createFromNode(
*/
public function getName() : string
{
return $this->node->consts[$this->positionInNode]->name;
return $this->node->consts[$this->positionInNode]->name->name;
}

/**
Expand Down Expand Up @@ -128,15 +128,15 @@ public function getModifiers() : int
*/
public function getStartLine() : int
{
return (int) $this->node->getAttribute('startLine', -1);
return $this->node->getStartLine();
}

/**
* Get the line number that this constant ends on.
*/
public function getEndLine() : int
{
return (int) $this->node->getAttribute('endLine', -1);
return $this->node->getEndLine();
}

public function getStartColumn() : int
Expand Down
Loading