summaryrefslogtreecommitdiff
path: root/vendor/sebastian/code-unit/src/Mapper.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/sebastian/code-unit/src/Mapper.php')
-rw-r--r--vendor/sebastian/code-unit/src/Mapper.php414
1 files changed, 414 insertions, 0 deletions
diff --git a/vendor/sebastian/code-unit/src/Mapper.php b/vendor/sebastian/code-unit/src/Mapper.php
new file mode 100644
index 000000000..a72b3b0dd
--- /dev/null
+++ b/vendor/sebastian/code-unit/src/Mapper.php
@@ -0,0 +1,414 @@
+<?php declare(strict_types=1);
+/*
+ * This file is part of sebastian/code-unit.
+ *
+ * (c) Sebastian Bergmann <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace SebastianBergmann\CodeUnit;
+
+use function array_keys;
+use function array_merge;
+use function array_unique;
+use function array_values;
+use function class_exists;
+use function explode;
+use function function_exists;
+use function interface_exists;
+use function ksort;
+use function method_exists;
+use function sort;
+use function sprintf;
+use function str_replace;
+use function strpos;
+use function trait_exists;
+use ReflectionClass;
+use ReflectionFunction;
+use ReflectionMethod;
+
+final class Mapper
+{
+ /**
+ * @psalm-return array<string,list<int>>
+ */
+ public function codeUnitsToSourceLines(CodeUnitCollection $codeUnits): array
+ {
+ $result = [];
+
+ foreach ($codeUnits as $codeUnit) {
+ $sourceFileName = $codeUnit->sourceFileName();
+
+ if (!isset($result[$sourceFileName])) {
+ $result[$sourceFileName] = [];
+ }
+
+ $result[$sourceFileName] = array_merge($result[$sourceFileName], $codeUnit->sourceLines());
+ }
+
+ foreach (array_keys($result) as $sourceFileName) {
+ $result[$sourceFileName] = array_values(array_unique($result[$sourceFileName]));
+
+ sort($result[$sourceFileName]);
+ }
+
+ ksort($result);
+
+ return $result;
+ }
+
+ /**
+ * @throws InvalidCodeUnitException
+ * @throws ReflectionException
+ */
+ public function stringToCodeUnits(string $unit): CodeUnitCollection
+ {
+ if (strpos($unit, '::') !== false) {
+ [$firstPart, $secondPart] = explode('::', $unit);
+
+ if (empty($firstPart) && $this->isUserDefinedFunction($secondPart)) {
+ return CodeUnitCollection::fromList(CodeUnit::forFunction($secondPart));
+ }
+
+ if ($this->isUserDefinedClass($firstPart)) {
+ if ($secondPart === '<public>') {
+ return $this->publicMethodsOfClass($firstPart);
+ }
+
+ if ($secondPart === '<!public>') {
+ return $this->protectedAndPrivateMethodsOfClass($firstPart);
+ }
+
+ if ($secondPart === '<protected>') {
+ return $this->protectedMethodsOfClass($firstPart);
+ }
+
+ if ($secondPart === '<!protected>') {
+ return $this->publicAndPrivateMethodsOfClass($firstPart);
+ }
+
+ if ($secondPart === '<private>') {
+ return $this->privateMethodsOfClass($firstPart);
+ }
+
+ if ($secondPart === '<!private>') {
+ return $this->publicAndProtectedMethodsOfClass($firstPart);
+ }
+
+ if ($this->isUserDefinedMethod($firstPart, $secondPart)) {
+ return CodeUnitCollection::fromList(CodeUnit::forClassMethod($firstPart, $secondPart));
+ }
+ }
+
+ if ($this->isUserDefinedInterface($firstPart)) {
+ return CodeUnitCollection::fromList(CodeUnit::forInterfaceMethod($firstPart, $secondPart));
+ }
+
+ if ($this->isUserDefinedTrait($firstPart)) {
+ return CodeUnitCollection::fromList(CodeUnit::forTraitMethod($firstPart, $secondPart));
+ }
+ } else {
+ if ($this->isUserDefinedClass($unit)) {
+ $units = [CodeUnit::forClass($unit)];
+
+ foreach ($this->reflectorForClass($unit)->getTraits() as $trait) {
+ if (!$trait->isUserDefined()) {
+ // @codeCoverageIgnoreStart
+ continue;
+ // @codeCoverageIgnoreEnd
+ }
+
+ $units[] = CodeUnit::forTrait($trait->getName());
+ }
+
+ return CodeUnitCollection::fromArray($units);
+ }
+
+ if ($this->isUserDefinedInterface($unit)) {
+ return CodeUnitCollection::fromList(CodeUnit::forInterface($unit));
+ }
+
+ if ($this->isUserDefinedTrait($unit)) {
+ return CodeUnitCollection::fromList(CodeUnit::forTrait($unit));
+ }
+
+ if ($this->isUserDefinedFunction($unit)) {
+ return CodeUnitCollection::fromList(CodeUnit::forFunction($unit));
+ }
+
+ $unit = str_replace('<extended>', '', $unit);
+
+ if ($this->isUserDefinedClass($unit)) {
+ return $this->classAndParentClassesAndTraits($unit);
+ }
+ }
+
+ throw new InvalidCodeUnitException(
+ sprintf(
+ '"%s" is not a valid code unit',
+ $unit
+ )
+ );
+ }
+
+ /**
+ * @psalm-param class-string $className
+ *
+ * @throws ReflectionException
+ */
+ private function publicMethodsOfClass(string $className): CodeUnitCollection
+ {
+ return $this->methodsOfClass($className, ReflectionMethod::IS_PUBLIC);
+ }
+
+ /**
+ * @psalm-param class-string $className
+ *
+ * @throws ReflectionException
+ */
+ private function publicAndProtectedMethodsOfClass(string $className): CodeUnitCollection
+ {
+ return $this->methodsOfClass($className, ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED);
+ }
+
+ /**
+ * @psalm-param class-string $className
+ *
+ * @throws ReflectionException
+ */
+ private function publicAndPrivateMethodsOfClass(string $className): CodeUnitCollection
+ {
+ return $this->methodsOfClass($className, ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PRIVATE);
+ }
+
+ /**
+ * @psalm-param class-string $className
+ *
+ * @throws ReflectionException
+ */
+ private function protectedMethodsOfClass(string $className): CodeUnitCollection
+ {
+ return $this->methodsOfClass($className, ReflectionMethod::IS_PROTECTED);
+ }
+
+ /**
+ * @psalm-param class-string $className
+ *
+ * @throws ReflectionException
+ */
+ private function protectedAndPrivateMethodsOfClass(string $className): CodeUnitCollection
+ {
+ return $this->methodsOfClass($className, ReflectionMethod::IS_PROTECTED | ReflectionMethod::IS_PRIVATE);
+ }
+
+ /**
+ * @psalm-param class-string $className
+ *
+ * @throws ReflectionException
+ */
+ private function privateMethodsOfClass(string $className): CodeUnitCollection
+ {
+ return $this->methodsOfClass($className, ReflectionMethod::IS_PRIVATE);
+ }
+
+ /**
+ * @psalm-param class-string $className
+ *
+ * @throws ReflectionException
+ */
+ private function methodsOfClass(string $className, int $filter): CodeUnitCollection
+ {
+ $units = [];
+
+ foreach ($this->reflectorForClass($className)->getMethods($filter) as $method) {
+ if (!$method->isUserDefined()) {
+ continue;
+ }
+
+ $units[] = CodeUnit::forClassMethod($className, $method->getName());
+ }
+
+ return CodeUnitCollection::fromArray($units);
+ }
+
+ /**
+ * @psalm-param class-string $className
+ *
+ * @throws ReflectionException
+ */
+ private function classAndParentClassesAndTraits(string $className): CodeUnitCollection
+ {
+ $units = [CodeUnit::forClass($className)];
+
+ $reflector = $this->reflectorForClass($className);
+
+ foreach ($this->reflectorForClass($className)->getTraits() as $trait) {
+ if (!$trait->isUserDefined()) {
+ // @codeCoverageIgnoreStart
+ continue;
+ // @codeCoverageIgnoreEnd
+ }
+
+ $units[] = CodeUnit::forTrait($trait->getName());
+ }
+
+ while ($reflector = $reflector->getParentClass()) {
+ if (!$reflector->isUserDefined()) {
+ break;
+ }
+
+ $units[] = CodeUnit::forClass($reflector->getName());
+
+ foreach ($reflector->getTraits() as $trait) {
+ if (!$trait->isUserDefined()) {
+ // @codeCoverageIgnoreStart
+ continue;
+ // @codeCoverageIgnoreEnd
+ }
+
+ $units[] = CodeUnit::forTrait($trait->getName());
+ }
+ }
+
+ return CodeUnitCollection::fromArray($units);
+ }
+
+ /**
+ * @psalm-param class-string $className
+ *
+ * @throws ReflectionException
+ */
+ private function reflectorForClass(string $className): ReflectionClass
+ {
+ try {
+ return new ReflectionClass($className);
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+ }
+
+ /**
+ * @throws ReflectionException
+ */
+ private function isUserDefinedFunction(string $functionName): bool
+ {
+ if (!function_exists($functionName)) {
+ return false;
+ }
+
+ try {
+ return (new ReflectionFunction($functionName))->isUserDefined();
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+ }
+
+ /**
+ * @throws ReflectionException
+ */
+ private function isUserDefinedClass(string $className): bool
+ {
+ if (!class_exists($className)) {
+ return false;
+ }
+
+ try {
+ return (new ReflectionClass($className))->isUserDefined();
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+ }
+
+ /**
+ * @throws ReflectionException
+ */
+ private function isUserDefinedInterface(string $interfaceName): bool
+ {
+ if (!interface_exists($interfaceName)) {
+ return false;
+ }
+
+ try {
+ return (new ReflectionClass($interfaceName))->isUserDefined();
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+ }
+
+ /**
+ * @throws ReflectionException
+ */
+ private function isUserDefinedTrait(string $traitName): bool
+ {
+ if (!trait_exists($traitName)) {
+ return false;
+ }
+
+ try {
+ return (new ReflectionClass($traitName))->isUserDefined();
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+ }
+
+ /**
+ * @throws ReflectionException
+ */
+ private function isUserDefinedMethod(string $className, string $methodName): bool
+ {
+ if (!class_exists($className)) {
+ // @codeCoverageIgnoreStart
+ return false;
+ // @codeCoverageIgnoreEnd
+ }
+
+ if (!method_exists($className, $methodName)) {
+ // @codeCoverageIgnoreStart
+ return false;
+ // @codeCoverageIgnoreEnd
+ }
+
+ try {
+ return (new ReflectionMethod($className, $methodName))->isUserDefined();
+ // @codeCoverageIgnoreStart
+ } catch (\ReflectionException $e) {
+ throw new ReflectionException(
+ $e->getMessage(),
+ (int) $e->getCode(),
+ $e
+ );
+ }
+ // @codeCoverageIgnoreEnd
+ }
+}