Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
<?php declare(strict_types=1);
2
 
3
namespace Composer\Pcre\PHPStan;
4
 
5
use Composer\Pcre\Preg;
6
use PhpParser\Node\Expr\StaticCall;
7
use PHPStan\Analyser\Scope;
8
use PHPStan\Analyser\SpecifiedTypes;
9
use PHPStan\Analyser\TypeSpecifier;
10
use PHPStan\Analyser\TypeSpecifierAwareExtension;
11
use PHPStan\Analyser\TypeSpecifierContext;
12
use PHPStan\Reflection\MethodReflection;
13
use PHPStan\TrinaryLogic;
14
use PHPStan\Type\Constant\ConstantArrayType;
15
use PHPStan\Type\Php\RegexArrayShapeMatcher;
16
use PHPStan\Type\StaticMethodTypeSpecifyingExtension;
17
use PHPStan\Type\TypeCombinator;
18
use PHPStan\Type\Type;
19
 
20
final class PregMatchTypeSpecifyingExtension implements StaticMethodTypeSpecifyingExtension, TypeSpecifierAwareExtension
21
{
22
    /**
23
     * @var TypeSpecifier
24
     */
25
    private $typeSpecifier;
26
 
27
    /**
28
     * @var RegexArrayShapeMatcher
29
     */
30
    private $regexShapeMatcher;
31
 
32
    public function __construct(RegexArrayShapeMatcher $regexShapeMatcher)
33
    {
34
        $this->regexShapeMatcher = $regexShapeMatcher;
35
    }
36
 
37
    public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void
38
    {
39
        $this->typeSpecifier = $typeSpecifier;
40
    }
41
 
42
    public function getClass(): string
43
    {
44
        return Preg::class;
45
    }
46
 
47
    public function isStaticMethodSupported(MethodReflection $methodReflection, StaticCall $node, TypeSpecifierContext $context): bool
48
    {
49
        return in_array($methodReflection->getName(), [
50
                'match', 'isMatch', 'matchStrictGroups', 'isMatchStrictGroups',
51
                'matchAll', 'isMatchAll', 'matchAllStrictGroups', 'isMatchAllStrictGroups'
52
            ], true)
53
            && !$context->null();
54
    }
55
 
56
    public function specifyTypes(MethodReflection $methodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes
57
    {
58
        $args = $node->getArgs();
59
        $patternArg = $args[0] ?? null;
60
        $matchesArg = $args[2] ?? null;
61
        $flagsArg = $args[3] ?? null;
62
 
63
        if (
64
            $patternArg === null || $matchesArg === null
65
        ) {
66
            return new SpecifiedTypes();
67
        }
68
 
69
        $flagsType = PregMatchFlags::getType($flagsArg, $scope);
70
        if ($flagsType === null) {
71
            return new SpecifiedTypes();
72
        }
73
 
74
        if (stripos($methodReflection->getName(), 'matchAll') !== false) {
75
            $matchedType = $this->regexShapeMatcher->matchAllExpr($patternArg->value, $flagsType, TrinaryLogic::createFromBoolean($context->true()), $scope);
76
        } else {
77
            $matchedType = $this->regexShapeMatcher->matchExpr($patternArg->value, $flagsType, TrinaryLogic::createFromBoolean($context->true()), $scope);
78
        }
79
 
80
        if ($matchedType === null) {
81
            return new SpecifiedTypes();
82
        }
83
 
84
        if (
85
            in_array($methodReflection->getName(), ['matchStrictGroups', 'isMatchStrictGroups', 'matchAllStrictGroups', 'isMatchAllStrictGroups'], true)
86
        ) {
87
            $matchedType = PregMatchFlags::removeNullFromMatches($matchedType);
88
        }
89
 
90
        $overwrite = false;
91
        if ($context->false()) {
92
            $overwrite = true;
93
            $context = $context->negate();
94
        }
95
 
96
        // @phpstan-ignore function.alreadyNarrowedType
97
        if (method_exists('PHPStan\Analyser\SpecifiedTypes', 'setRootExpr')) {
98
            $typeSpecifier = $this->typeSpecifier->create(
99
                $matchesArg->value,
100
                $matchedType,
101
                $context,
102
                $scope
103
            )->setRootExpr($node);
104
 
105
            return $overwrite ? $typeSpecifier->setAlwaysOverwriteTypes() : $typeSpecifier;
106
        }
107
 
108
        // @phpstan-ignore arguments.count
109
        return $this->typeSpecifier->create(
110
            $matchesArg->value,
111
            $matchedType,
112
            $context,
113
            // @phpstan-ignore argument.type
114
            $overwrite,
115
            $scope,
116
            $node
117
        );
118
    }
119
}