Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@

namespace Magento\CodeMessDetector\Rule\Design;

use Magento\Framework\Session\SessionManagerInterface;
use Magento\Framework\Stdlib\Cookie\CookieReaderInterface;
use PDepend\Source\AST\ASTClass;
use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Node\ClassNode;
use PHPMD\Rule\ClassAware;
use ReflectionClass;
use ReflectionException;
use ReflectionParameter;

/**
* Session and Cookies must be used only in HTML Presentation layer.
Expand Down Expand Up @@ -105,7 +110,7 @@ private function isControllerPlugin(\ReflectionClass $class): bool
foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
if (preg_match('/^(after|around|before).+/i', $method->getName())) {
try {
$argument = $method->getParameters()[0]->getClass();
$argument = $this->getParameterClass($method->getParameters()[0]);
} catch (\Throwable $exception) {
//Non-existing class (autogenerated perhaps) or doesn't have an argument.
continue;
Expand Down Expand Up @@ -134,7 +139,7 @@ private function isBlockPlugin(\ReflectionClass $class): bool
foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
if (preg_match('/^(after|around|before).+/i', $method->getName())) {
try {
$argument = $method->getParameters()[0]->getClass();
$argument = $this->getParameterClass($method->getParameters()[0]);
} catch (\Throwable $exception) {
//Non-existing class (autogenerated perhaps) or doesn't have an argument.
continue;
Expand Down Expand Up @@ -164,14 +169,16 @@ private function doesUseRestrictedClasses(\ReflectionClass $class): bool
if ($constructor) {
foreach ($constructor->getParameters() as $argument) {
try {
if ($class = $argument->getClass()) {
if ($class->isSubclassOf(\Magento\Framework\Session\SessionManagerInterface::class)
|| $class->getName() === \Magento\Framework\Session\SessionManagerInterface::class
|| $class->isSubclassOf(\Magento\Framework\Stdlib\Cookie\CookieReaderInterface::class)
|| $class->getName() === \Magento\Framework\Stdlib\Cookie\CookieReaderInterface::class
) {
return true;
}
$class = $this->getParameterClass($argument);
if ($class === null) {
continue;
}
if ($class->isSubclassOf(SessionManagerInterface::class)
|| $class->getName() === SessionManagerInterface::class
|| $class->isSubclassOf(CookieReaderInterface::class)
|| $class->getName() === CookieReaderInterface::class
) {
return true;
}
} catch (\ReflectionException $exception) {
//Failed to load the argument's class information
Expand All @@ -183,6 +190,22 @@ private function doesUseRestrictedClasses(\ReflectionClass $class): bool
return false;
}

/**
* Get class by reflection parameter
*
* @param ReflectionParameter $reflectionParameter
* @return ReflectionClass|null
* @throws ReflectionException
*/
private function getParameterClass(ReflectionParameter $reflectionParameter): ?ReflectionClass
{
$parameterType = $reflectionParameter->getType();

return $parameterType && !$parameterType->isBuiltin()
? new ReflectionClass($parameterType->getName())
: null;
}

/**
* @inheritdoc
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
use Laminas\Code\Reflection\ClassReflection;
use Laminas\Code\Reflection\FileReflection;
use Laminas\Code\Reflection\ParameterReflection;
use ReflectionClass;
use ReflectionException;
use ReflectionParameter;

/**
* Provide dependencies for the file
Expand Down Expand Up @@ -39,7 +42,7 @@ public function getDependencies(FileReflection $fileReflection)
foreach ($method->getParameters() as $parameter) {
try {
/** @var ParameterReflection $parameter */
$dependency = $parameter->getClass();
$dependency = $this->getParameterClass($parameter);
if ($dependency instanceof ClassReflection) {
$this->dependencies[] = $dependency->getName();
}
Expand All @@ -56,4 +59,20 @@ public function getDependencies(FileReflection $fileReflection)

return $this->dependencies;
}

/**
* Get class by reflection parameter
*
* @param ReflectionParameter $reflectionParameter
* @return ReflectionClass|null
* @throws ReflectionException
*/
private function getParameterClass(ReflectionParameter $reflectionParameter): ?ReflectionClass
{
$parameterType = $reflectionParameter->getType();

return $parameterType && !$parameterType->isBuiltin()
? new ReflectionClass($parameterType->getName())
: null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
namespace Magento\Test\Integrity;

use Magento\Framework\App\Utility\Files;
use ReflectionClass;
use ReflectionException;
use ReflectionParameter;

/**
* Tests @api annotated code integrity
Expand Down Expand Up @@ -277,7 +280,7 @@ private function checkParameters($class, \ReflectionMethod $method, array $nonPu
&& !$parameter->getType()->isBuiltin()
&& !$this->isGenerated($parameter->getType()->getName())
) {
$parameterClass = $parameter->getClass();
$parameterClass = $this->getParameterClass($parameter);
/*
* We don't want to check integrity of @api coverage of classes
* that belong to different vendors, because it is too complicated.
Expand All @@ -286,7 +289,7 @@ private function checkParameters($class, \ReflectionMethod $method, array $nonPu
* we don't want to fail test, because Zend is considered public by default,
* and we don't care if Zend classes are @api-annotated
*/
if (!$parameterClass->isInternal()
if ($parameterClass && !$parameterClass->isInternal()
&& $this->areClassesFromSameVendor($parameterClass->getName(), $class)
&& !$this->isPublished($parameterClass)
) {
Expand All @@ -296,4 +299,20 @@ private function checkParameters($class, \ReflectionMethod $method, array $nonPu
}
return $nonPublishedClasses;
}

/**
* Get class by reflection parameter
*
* @param ReflectionParameter $reflectionParameter
* @return ReflectionClass|null
* @throws ReflectionException
*/
private function getParameterClass(ReflectionParameter $reflectionParameter): ?ReflectionClass
{
$parameterType = $reflectionParameter->getType();

return $parameterType && !$parameterType->isBuiltin()
? new ReflectionClass($parameterType->getName())
: null;
}
}
50 changes: 35 additions & 15 deletions lib/internal/Magento/Framework/Code/Generator/EntityAbstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
namespace Magento\Framework\Code\Generator;

use Laminas\Code\Generator\ValueGenerator;
use ReflectionClass;
use ReflectionException;
use ReflectionParameter;

/**
* Abstract entity
Expand Down Expand Up @@ -323,29 +326,46 @@ protected function _getNullDefaultValue()
private function extractParameterType(
\ReflectionParameter $parameter
): ?string {
if (!$parameter->hasType()) {
return null;
}

/** @var string|null $typeName */
$typeName = null;
if ($parameter->hasType()) {
if ($parameter->isArray()) {
$typeName = 'array';
} elseif ($parameter->getClass()) {
$typeName = $this->_getFullyQualifiedClassName(
$parameter->getClass()->getName()
);
} elseif ($parameter->isCallable()) {
$typeName = 'callable';
} else {
$typeName = $parameter->getType()->getName();
}

if ($parameter->allowsNull()) {
$typeName = '?' .$typeName;
}
if ($parameter->isArray()) {
$typeName = 'array';
} elseif ($parameterClass = $this->getParameterClass($parameter)) {
$typeName = $this->_getFullyQualifiedClassName($parameterClass->getName());
} elseif ($parameter->isCallable()) {
$typeName = 'callable';
} else {
$typeName = $parameter->getType()->getName();
}

if ($parameter->allowsNull()) {
$typeName = '?' . $typeName;
}

return $typeName;
}

/**
* Get class by reflection parameter
*
* @param ReflectionParameter $reflectionParameter
* @return ReflectionClass|null
* @throws ReflectionException
*/
private function getParameterClass(ReflectionParameter $reflectionParameter): ?ReflectionClass
{
$parameterType = $reflectionParameter->getType();

return $parameterType && !$parameterType->isBuiltin()
? new ReflectionClass($parameterType->getName())
: null;
}

/**
* Extract parameter default value
*
Expand Down
28 changes: 25 additions & 3 deletions lib/internal/Magento/Framework/Code/Reader/ArgumentsReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
*/
namespace Magento\Framework\Code\Reader;

use ReflectionClass;
use ReflectionException;
use ReflectionParameter;

/**
* The class arguments reader
*/
Expand Down Expand Up @@ -98,11 +102,13 @@ public function getConstructorArguments(\ReflectionClass $class, $groupByPositio
*/
private function processType(\ReflectionClass $class, \Laminas\Code\Reflection\ParameterReflection $parameter)
{
if ($parameter->getClass()) {
return NamespaceResolver::NS_SEPARATOR . $parameter->getClass()->getName();
$parameterClass = $this->getParameterClass($parameter);

if ($parameterClass) {
return NamespaceResolver::NS_SEPARATOR . $parameterClass->getName();
}

$type = $parameter->detectType();
$type = $parameter->detectType();

if ($type === 'null') {
return null;
Expand All @@ -121,6 +127,22 @@ private function processType(\ReflectionClass $class, \Laminas\Code\Reflection\P
return $type;
}

/**
* Get class by reflection parameter
*
* @param ReflectionParameter $reflectionParameter
* @return ReflectionClass|null
* @throws ReflectionException
*/
private function getParameterClass(ReflectionParameter $reflectionParameter): ?ReflectionClass
{
$parameterType = $reflectionParameter->getType();

return $parameterType && !$parameterType->isBuiltin()
? new ReflectionClass($parameterType->getName())
: null;
}

/**
* Get arguments of parent __construct call
*
Expand Down
38 changes: 30 additions & 8 deletions lib/internal/Magento/Framework/Code/Reader/ClassReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
*/
namespace Magento\Framework\Code\Reader;

use ReflectionClass;
use ReflectionException;
use ReflectionParameter;

/**
* Class ClassReader
*/
Expand All @@ -17,46 +21,64 @@ class ClassReader implements ClassReaderInterface
*
* @param string $className
* @return array|null
* @throws \ReflectionException
* @throws ReflectionException
*/
public function getConstructor($className)
{
$class = new \ReflectionClass($className);
$class = new ReflectionClass($className);
$result = null;
$constructor = $class->getConstructor();
if ($constructor) {
$result = [];
/** @var $parameter \ReflectionParameter */
/** @var $parameter ReflectionParameter */
foreach ($constructor->getParameters() as $parameter) {
try {
$parameterClass = $this->getParameterClass($parameter);

$result[] = [
$parameter->getName(),
$parameter->getClass() !== null ? $parameter->getClass()->getName() : null,
$parameterClass ? $parameterClass->getName() : null,
!$parameter->isOptional() && !$parameter->isDefaultValueAvailable(),
$this->getReflectionParameterDefaultValue($parameter),
$parameter->isVariadic(),
];
} catch (\ReflectionException $e) {
} catch (ReflectionException $e) {
$message = sprintf(
'Impossible to process constructor argument %s of %s class',
$parameter->__toString(),
$className
);
throw new \ReflectionException($message, 0, $e);
throw new ReflectionException($message, 0, $e);
}
}
}

return $result;
}

/**
* Get class by reflection parameter
*
* @param ReflectionParameter $reflectionParameter
* @return ReflectionClass|null
* @throws ReflectionException
*/
private function getParameterClass(ReflectionParameter $reflectionParameter): ?ReflectionClass
{
$parameterType = $reflectionParameter->getType();

return $parameterType && !$parameterType->isBuiltin()
? new ReflectionClass($parameterType->getName())
: null;
}

/**
* Get reflection parameter default value
*
* @param \ReflectionParameter $parameter
* @param ReflectionParameter $parameter
* @return array|mixed|null
*/
private function getReflectionParameterDefaultValue(\ReflectionParameter $parameter)
private function getReflectionParameterDefaultValue(ReflectionParameter $parameter)
{
if ($parameter->isVariadic()) {
return [];
Expand Down
Loading