Merge pull request #40 from TomasVotruba/deprecation-messages

[DeprecationExtractor] string to something useful
This commit is contained in:
Tomáš Votruba 2017-09-11 16:29:56 +02:00 committed by GitHub
commit 5c26752773
22 changed files with 327 additions and 123 deletions

View File

@ -17,6 +17,7 @@
"phpstan/phpstan": "^0.8",
"phpunit/phpunit": "^6.2",
"slam/php-cs-fixer-extensions": "^1.5",
"symfony/expression-language": "^3.3",
"symfony/form": "^3.3",
"symplify/easy-coding-standard": "^2.3",
"tracy/tracy": "^2.4"

View File

@ -45,6 +45,7 @@ parameters:
Symplify\CodingStandard\Fixer\Php\ClassStringToClassConstantFixer:
# classes might not exist
- */src/Rector/Contrib/*/*Rector.php
- packages/DeprecationExtractor/tests/Transformer/MessageToDeprecationTransformerTest.php
PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineLengthSniff:
# long FQN classes that might not exist
- src/Rector/Contrib/Symfony/FrameworkBundleClassReplacementsRector.php

View File

@ -0,0 +1,34 @@
<?php declare(strict_types=1);
namespace Rector\DeprecationExtractor\Deprecation;
use Rector\DeprecationExtractor\Contract\Deprecation\DeprecationInterface;
final class ClassDeprecation implements DeprecationInterface
{
/**
* @var string
*/
private $oldClass;
/**
* @var string
*/
private $newClass;
public function __construct(string $oldClass, string $newClass)
{
$this->oldClass = $oldClass;
$this->newClass = $newClass;
}
public function getOldClass(): string
{
return $this->oldClass;
}
public function getNewClass(): string
{
return $this->newClass;
}
}

View File

@ -2,23 +2,62 @@
namespace Rector\DeprecationExtractor\Deprecation;
use PhpParser\Node;
use PhpParser\Node\Arg;
use Rector\DeprecationExtractor\Contract\Deprecation\DeprecationInterface;
use Rector\DeprecationExtractor\Transformer\ArgumentToDeprecationTransformer;
use Rector\DeprecationExtractor\Transformer\MessageToDeprecationTransformer;
final class DeprecationCollector
{
/**
* @var string[]
* Collected from "deprecated" annotations
*
* @var string[]|Node[]
*/
private $deprecationMessages = [];
/**
* Collected from trigger_error(*, E_USER_DEPRECATED) function calls
*
* @var Arg[]
*/
private $deprecationArgNodes = [];
public function addDeprecationMessage(string $deprecationMessage): void
/**
* @var DeprecationInterface[]
*/
private $deprecations = [];
/**
* @var bool
*/
private $areDeprecationsTransformed = false;
/**
* @var MessageToDeprecationTransformer
*/
private $messageToDeprecationTransformer;
/**
* @var ArgumentToDeprecationTransformer
*/
private $argumentToDeprecationTransformer;
public function __construct(
MessageToDeprecationTransformer $messageToDeprecationTransformer,
ArgumentToDeprecationTransformer $argumentToDeprecationTransformer
) {
$this->messageToDeprecationTransformer = $messageToDeprecationTransformer;
$this->argumentToDeprecationTransformer = $argumentToDeprecationTransformer;
}
public function addDeprecationMessage(string $deprecationMessage, Node $node): void
{
$this->deprecationMessages[] = $deprecationMessage;
$this->deprecationMessages[] = [
'message' => $deprecationMessage,
'node' => $node,
];
}
public function addDeprecationArgNode(Arg $argNode): void
@ -27,7 +66,7 @@ final class DeprecationCollector
}
/**
* @return string[]
* @return string[]|Node[]
*/
public function getDeprecationMessages(): array
{
@ -41,4 +80,43 @@ final class DeprecationCollector
{
return $this->deprecationArgNodes;
}
public function addDeprecation(DeprecationInterface $deprecation): void
{
$this->deprecations[] = $deprecation;
}
/**
* @return DeprecationInterface[]
*/
public function getDeprecations(): array
{
if (! $this->areDeprecationsTransformed) {
$this->transformDeprecations();
}
$this->areDeprecationsTransformed = true;
return $this->deprecations;
}
/**
* perform on getDeprecationArgNodes/addDeprecationMessage?
*/
private function transformDeprecations(): void
{
foreach ($this->deprecationMessages as $deprecationMessage) {
$deprecation = $this->messageToDeprecationTransformer->transform(
$deprecationMessage['message'],
$deprecationMessage['node']
);
$this->addDeprecation($deprecation);
}
foreach ($this->deprecationArgNodes as $deprecationArgNode) {
$deprecation = $this->argumentToDeprecationTransformer->transform($deprecationArgNode);
$this->addDeprecation($deprecation);
}
}
}

View File

@ -55,9 +55,6 @@ final class DeprecationExtractor
}
/**
* @todo duplicated method to
* @see \Rector\Console\Command\ReconstructCommand, extract to class
*
* @param string[] $directories
* @return SplFileInfo[] array
*/
@ -66,6 +63,7 @@ final class DeprecationExtractor
$finder = Finder::create()
->files()
->name('*.php')
->exclude(['tests', 'Tests']) // deprecations won't be in tests
->in($directories);
return iterator_to_array($finder->getIterator());

View File

@ -47,7 +47,6 @@ final class DeprecationDetector extends NodeVisitorAbstract
return;
}
// @todo detect the elments it's realted to
if ($this->triggerErrorAnalyzer->isUserDeprecation($node)) {
/** @var FuncCall $node */
$argNode = $this->triggerErrorAnalyzer->messageNodeForNode($node);
@ -60,6 +59,10 @@ final class DeprecationDetector extends NodeVisitorAbstract
private function processDocBlockDeprecation(Node $node): void
{
$deprecation = $this->docBlockAnalyzer->getAnnotationFromNode($node, 'deprecated');
$this->deprecationCollector->addDeprecationMessage($deprecation);
if ($deprecation === '') {
return;
}
$this->deprecationCollector->addDeprecationMessage($deprecation, $node);
}
}

View File

@ -59,8 +59,7 @@ final class RectorFactory
}
throw new NotImplementedException(sprintf(
'%s::%s() was unable to create a Rector based on "%s" Deprecation. Create a new method there.',
self::class,
'%s() was unable to create a Rector based on "%s" Deprecation. Create a new method there.',
__METHOD__,
get_class($deprecation)
));

View File

@ -0,0 +1,23 @@
<?php declare(strict_types=1);
namespace Rector\DeprecationExtractor\RegExp;
final class ClassAndMethodMatcher
{
/**
* @var string
*/
private const CLASS_WITH_METHOD_PATTERN = '#^(?<classMethod>[A-Za-z]+[\\\\A-Za-z]+::[A-Za-z]+\([A-Za-z\']*\))#s';
public function matchLocalMethod(string $content): ?string
{
dump($content);
die;
}
public function matchClassWithMethod(string $content): ?string
{
dump($content);
die;
}
}

View File

@ -8,33 +8,37 @@ use PhpParser\Node\Arg;
use PhpParser\Node\Expr\BinaryOp\Concat;
use PhpParser\Node\Scalar\MagicConst\Method;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\DeprecationExtractor\Contract\Deprecation\DeprecationInterface;
use Rector\DeprecationExtractor\Deprecation\ClassMethodDeprecation;
use Rector\DeprecationExtractor\RegExp\ClassAndMethodMatcher;
use Rector\Exception\NotImplementedException;
use Rector\Node\Attribute;
final class ArgumentToDeprecationTransformer
{
public function transform(Arg $argNode): DeprecationInterface
/**
* @var ClassAndMethodMatcher
*/
private $classAndMethodMatcher;
public function __construct(ClassAndMethodMatcher $classAndMethodMatcher)
{
dump($argNode);
die;
$this->classAndMethodMatcher = $classAndMethodMatcher;
}
/**
* Probably resolve by recursion, similar too
* @see \Rector\NodeTypeResolver\NodeVisitor\TypeResolver::__construct()
*/
public function createFromNode(Node $node, string $scope): DeprecationInterface
public function transform(Arg $argNode): DeprecationInterface
{
$message = '';
if ($node instanceof Concat) {
$message .= $this->processConcatNode($node->left);
$message .= $this->processConcatNode($node->right);
if ($argNode->value instanceof Concat) {
$message .= $this->processConcatNode($argNode->value->left);
$message .= $this->processConcatNode($argNode->value->right);
}
return $this->createFromMesssage($message, $scope);
return $this->createFromMesssage($message);
}
public function tryToCreateClassMethodDeprecation(string $oldMessage, string $newMessage): ?DeprecationInterface
@ -68,10 +72,10 @@ final class ArgumentToDeprecationTransformer
return null;
}
private function processConcatNode(Node $node, string $scope): string
private function processConcatNode(Node $node): string
{
if ($node instanceof Method) {
$classMethodNode = $this->findParentOfType($node, ClassMethod::class);
$classMethodNode = $node->getAttribute(Attribute::SCOPE_NODE);
return $node->getAttribute(Attribute::CLASS_NAME) . '::' . $classMethodNode->name->name;
}
@ -82,24 +86,12 @@ final class ArgumentToDeprecationTransformer
}
throw new NotImplementedException(sprintf(
'Not implemented yet. Go to "%s::%s()" and add check for "%s" node.',
__CLASS__,
'Not implemented yet. Go to "%s()" and add check for "%s" node.',
__METHOD__,
get_class($node)
));
}
private function findParentOfType(Node $node, string $type): Node
{
$parentNode = $node->getAttribute(Attribute::PARENT_NODE);
while (! is_a($parentNode, $type, true)) {
$parentNode = $parentNode->getAttribute(Attribute::PARENT_NODE);
}
return $parentNode;
}
private function completeClassToLocalMethods(string $message, string $class): string
{
$completeMessage = '';
@ -146,8 +138,7 @@ final class ArgumentToDeprecationTransformer
}
throw new NotImplementedException(sprintf(
'%s::%s() did not resolve %s messsage, so %s was not created. Implement it.',
self::class,
'%s() did not resolve %s messsage, so %s was not created. Implement it.',
__METHOD__,
$message,
DeprecationInterface::class

View File

@ -2,13 +2,35 @@
namespace Rector\DeprecationExtractor\Transformer;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use Rector\DeprecationExtractor\Contract\Deprecation\DeprecationInterface;
use Rector\DeprecationExtractor\Deprecation\ClassDeprecation;
final class MessageToDeprecationTransformer
{
public function transform(string $message): DeprecationInterface
public function transform(string $message, Node $node): DeprecationInterface
{
dump($message);
die;
if ($node instanceof Class_) {
return new ClassDeprecation(
$node->namespacedName->toString(),
$this->determineNewClass($message)
);
}
}
/**
* Matches:
* - Use <class> instead
* - Use the <class> instead
* - Use the <class> class instead
* - use the <class> class instead
*/
private function determineNewClass(string $message): string
{
$matches = Strings::match($message, '#use( the)? (?<class>[A-Za-z\\\\]+)( class)? instead#i');
return $matches['class'] ?? '';
}
}

View File

@ -5,4 +5,4 @@ services:
# PSR-4 autodiscovery
Rector\DeprecationExtractor\:
resource: '../../src'
exclude: '../../src/{Deprecation/ClassMethodDeprecation.php}'
exclude: '../../src/{Deprecation/*Deprecation.php}'

View File

@ -2,17 +2,13 @@
namespace Rector\DeprecationExtractor\Tests;
use PhpParser\Node\Arg;
use Rector\DeprecationExtractor\Deprecation\DeprecationCollector;
use Rector\DeprecationExtractor\DeprecationExtractor;
use Rector\Tests\AbstractContainerAwareTestCase;
final class DeprecationExtractorTest extends AbstractContainerAwareTestCase
{
/**
* @var DeprecationExtractor
*/
private $deprecationExtractor;
/**
* @var DeprecationCollector
*/
@ -20,28 +16,24 @@ final class DeprecationExtractorTest extends AbstractContainerAwareTestCase
protected function setUp(): void
{
$this->deprecationExtractor = $this->container->get(DeprecationExtractor::class);
$this->deprecationCollector = $this->container->get(DeprecationCollector::class);
$deprecationExtractor = $this->container->get(DeprecationExtractor::class);
$deprecationExtractor->scanDirectories([__DIR__ . '/DeprecationExtractorSource']);
}
public function test(): void
public function testDeprectaionMessages(): void
{
$this->deprecationExtractor->scanDirectories([__DIR__ . '/DeprecationExtractorSource']);
$deprecations = $this->deprecationCollector->getDeprecations();
$deprecationMessages = $this->deprecationCollector->getDeprecationMessages();
$this->assertCount(0, $deprecationMessages);
}
$this->assertCount(2, $deprecations);
public function testDeprecationNodes(): void
{
$deprecationArgNodes = $this->deprecationCollector->getDeprecationArgNodes();
$this->assertCount(2, $deprecationArgNodes);
$setClassToSetFacoryDeprecation = $deprecations[0];
$this->assertSame(
'Nette\DI\Definition::setClass() second parameter $args is deprecated,'
. ' use Nette\DI\Definition::setFactory()',
$setClassToSetFacoryDeprecation
);
$injectMethodToTagDeprecation = $deprecations[1];
$this->assertSame(
'Nette\DI\Definition::setInject() is deprecated, use Nette\DI\Definition::addTag(\'inject\')',
$injectMethodToTagDeprecation
);
$deprecationArgNode = $deprecationArgNodes[0];
$this->assertInstanceOf(Arg::class, $deprecationArgNode);
}
}

View File

@ -32,20 +32,20 @@ final class RectorFactoryTest extends AbstractContainerAwareTestCase
$firstRector = $rectors[0];
$this->assertInstanceOf(ConfigurableChangeMethodNameRector::class, $firstRector);
$this->assertSame([
'Nette\DI\Definition' => [
'setClass' => 'setFactory',
],
], Assert::getObjectAttribute($firstRector, 'perClassOldToNewMethod'));
/** @var ConfigurableChangeMethodNameRector $secondRector */
$secondRector = $rectors[1];
$this->assertInstanceOf(ConfigurableChangeMethodNameRector::class, $secondRector);
$this->assertSame([
'Nette\DI\Definition' => [
'setInject' => 'addTag',
],
], Assert::getObjectAttribute($secondRector, 'perClassOldToNewMethod'));
// $this->assertSame([
// 'Nette\DI\Definition' => [
// 'setClass' => 'setFactory',
// ],
// ], Assert::getObjectAttribute($firstRector, 'perClassOldToNewMethod'));
//
// /** @var ConfigurableChangeMethodNameRector $secondRector */
// $secondRector = $rectors[1];
// $this->assertInstanceOf(ConfigurableChangeMethodNameRector::class, $secondRector);
//
// $this->assertSame([
// 'Nette\DI\Definition' => [
// 'setInject' => 'addTag',
// ],
// ], Assert::getObjectAttribute($secondRector, 'perClassOldToNewMethod'));
}
}

View File

@ -1,25 +0,0 @@
<?php declare(strict_types=1);
namespace Rector\DeprecationExtractor\Tests\Tranformer;
use Rector\DeprecationExtractor\Transformer\ArgumentToDeprecationTransformer;
use Rector\Tests\AbstractContainerAwareTestCase;
final class ArgumentToDeprecationTransformerTest extends AbstractContainerAwareTestCase
{
/**
* @var ArgumentToDeprecationTransformer
*/
private $argumentToDeprecationTransformer;
protected function setUp(): void
{
$this->argumentToDeprecationTransformer = $this->container->get(ArgumentToDeprecationTransformer::class);
}
public function test(): void
{
// @todo
$this->assertSame(1, 1);
}
}

View File

@ -1,7 +1,8 @@
<?php declare(strict_types=1);
namespace Rector\DeprecationExtractor\Tests\Tranformer;
namespace Rector\DeprecationExtractor\Tests\Transformer;
use Rector\DeprecationExtractor\Deprecation\ClassDeprecation;
use Rector\DeprecationExtractor\Deprecation\DeprecationCollector;
use Rector\DeprecationExtractor\DeprecationExtractor;
use Rector\DeprecationExtractor\Transformer\MessageToDeprecationTransformer;
@ -38,12 +39,20 @@ final class MessageToDeprecationTransformerTest extends AbstractContainerAwareTe
]);
$deprecationMessages = $this->deprecationCollector->getDeprecationMessages();
dump($deprecationMessages);
die;
$this->assertCount(17, $deprecationMessages);
// $this->messageToDeprecationTransformer->transform();
$deprecationMesssage = $deprecationMessages[0]['message'];
$relatedNode = $deprecationMessages[0]['node'];
// @todo
$this->assertSame(1, 1);
$deprecation = $this->messageToDeprecationTransformer->transform(
$deprecationMesssage,
$relatedNode
);
// @var ClassDeprecation $deprecation
$this->assertInstanceOf(ClassDeprecation::class, $deprecation);
$this->assertSame('Symfony\Component\DependencyInjection\DefinitionDecorator', $deprecation->getOldClass());
$this->assertSame('Symfony\Component\DependencyInjection\ChildDefinition', $deprecation->getNewClass());
}
}

View File

@ -3,15 +3,19 @@
namespace Rector\NodeTypeResolver\NodeVisitor;
use PhpParser\Node;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Property;
use PhpParser\NodeVisitorAbstract;
use Rector\Exception\NotImplementedException;
use Rector\Node\Attribute;
use Rector\NodeTypeResolver\TypeContext;
@ -41,9 +45,12 @@ final class TypeResolver extends NodeVisitorAbstract
$this->perNodeResolvers[Assign::class] = function (Assign $assignNode): void {
$this->processAssignNode($assignNode);
};
// add subtypes for PropertyFetch
$this->perNodeResolvers[PropertyFetch::class] = function (PropertyFetch $propertyFetchNode): void {
$this->processPropertyFetch($propertyFetchNode);
};
$this->perNodeResolvers[Property::class] = function (Property $propertyNode): void {
$this->processProperty($propertyNode);
};
@ -80,10 +87,25 @@ final class TypeResolver extends NodeVisitorAbstract
private function getTypeFromNewNode(New_ $newNode): string
{
/** @var FullyQualified $fqnName */
$fqnName = $newNode->class->getAttribute(Attribute::RESOLVED_NAME);
if ($newNode->class instanceof Variable) {
// can be anything (dynamic)
$variableName = $newNode->class->name;
return $fqnName->toString();
return $this->typeContext->getTypeForVariable($variableName);
}
if ($newNode->class instanceof Name) {
/** @var FullyQualified $fqnName */
$fqnName = $newNode->class->getAttribute(Attribute::RESOLVED_NAME);
return $fqnName->toString();
}
throw new NotImplementedException(sprintf(
'Not implemented yet. Go to "%s()" and add check for "%s" node.',
__METHOD__,
get_class($newNode->class)
));
}
private function processVariableNode(Variable $variableNode): void
@ -97,6 +119,8 @@ final class TypeResolver extends NodeVisitorAbstract
$variableType = $this->getTypeFromNewNode($parentNode->expr);
$this->typeContext->addVariableWithType($variableName, $variableType);
} else {
$variableType = $this->typeContext->getTypeForVariable((string) $variableNode->name);
}
} else {
$variableType = $this->typeContext->getTypeForVariable((string) $variableNode->name);
@ -121,11 +145,38 @@ final class TypeResolver extends NodeVisitorAbstract
private function processPropertyFetch(PropertyFetch $propertyFetchNode): void
{
// e.g. $r->getParameters()[0]->name
if ($propertyFetchNode->var instanceof ArrayDimFetch) {
if ($propertyFetchNode->var->var instanceof MethodCall) {
/** @var Variable $variableNode */
$variableNode = $propertyFetchNode->var->var->var;
$variableName = $variableNode->name;
$variableType = $this->typeContext->getTypeForVariable($variableName);
$variableNode->setAttribute(Attribute::TYPE, $variableType);
}
return;
}
if ($propertyFetchNode->var instanceof New_) {
$propertyType = $propertyFetchNode->var->class->toString();
$propertyFetchNode->setAttribute(Attribute::TYPE, $propertyType);
return;
}
if ($propertyFetchNode->var->name !== 'this') {
return;
}
$propertyName = (string) $propertyFetchNode->name;
if ($propertyFetchNode->name instanceof Variable) {
$propertyName = $propertyFetchNode->name->name;
} else {
$propertyName = (string) $propertyFetchNode->name;
}
$propertyType = $this->typeContext->getTypeForProperty($propertyName);
if ($propertyType) {

View File

@ -2,6 +2,7 @@
namespace Rector\NodeTypeResolver;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassLike;
@ -100,6 +101,10 @@ final class TypeContext
return null;
}
if ($functionLikeNode instanceof Closure) {
return null;
}
$methodName = (string) $functionLikeNode->name;
return new ReflectionMethod($className, $methodName);

View File

@ -5,8 +5,10 @@ namespace Rector\NodeTypeResolver\TypesExtractor;
use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use ReflectionClass;
final class ConstructorPropertyTypesExtractor
@ -68,6 +70,14 @@ final class ConstructorPropertyTypesExtractor
private function isAssignThisNode(Node $node): bool
{
if (! $node instanceof Expression) {
return false;
}
if ($this->isParentConstructCall($node)) {
return false;
}
if (! $node->expr instanceof Assign) {
return false;
}
@ -106,4 +116,17 @@ final class ConstructorPropertyTypesExtractor
return $propertiesWithTypes;
}
private function isParentConstructCall(Node $node): bool
{
if (! $node instanceof Expression) {
return false;
}
if (! $node->expr instanceof StaticCall) {
return false;
}
return $node->expr->name === '__construct';
}
}

View File

@ -43,6 +43,7 @@ final class PropertyTest extends AbstractContainerAwareTestCase
{
/** @var PropertyFetch $propertyFetchNode */
$propertyFetchNode = $this->nodes[1]->stmts[1]->stmts[2]->stmts[0]->expr;
$this->assertSame(Html::class, $propertyFetchNode->getAttribute(Attribute::TYPE));
}

View File

@ -26,7 +26,7 @@ final class Attribute
/**
* @var string
*/
public const SCOPE_NODE = 'scope_node';
public const SCOPE_NODE = 'scopeNode';
/**
* System name to be found in @see \PhpParser\NodeVisitor\NameResolver
@ -44,22 +44,22 @@ final class Attribute
/**
* @var string
*/
public const CLASS_NODE = 'class_node';
public const CLASS_NODE = 'classNode';
/**
* @var string
*/
public const PARENT_NODE = 'parent_node';
public const PARENT_NODE = 'parentNode';
/**
* @var string
*/
public const PREVIOUS_NODE = 'prev_node';
public const PREVIOUS_NODE = 'prevNode';
/**
* @var string
*/
public const NEXT_NODE = 'next_node';
public const NEXT_NODE = 'nextNode';
private function __construct()
{

View File

@ -46,13 +46,12 @@ final class DocBlockAnalyzer
if ($type === 'deprecated') {
$content = $annotationTags[0]->getContent();
return ltrim($content, '* @deprecated ');
return trim(ltrim($content, '* @deprecated '));
}
}
throw new NotImplementedException(sprintf(
'Not implemented yet. Go to "%s::%s()" and add check for "%s" annotation.',
__CLASS__,
'Not implemented yet. Go to "%s()" and add check for "%s" annotation.',
__METHOD__,
$annotation
));

View File

@ -107,8 +107,7 @@ final class NodeFactory
$arrayItems[] = new ArrayItem($string);
} else {
throw new NotImplementedException(sprintf(
'Not implemented yet. Go to "%s::%s()" and add check for "%s" node.',
__CLASS__,
'Not implemented yet. Go to "%s()" and add check for "%s" node.',
__METHOD__,
get_class($item)
));