blob: fc6fd2a796ee6df57374784be8c098882529034f [file] [log] [blame]
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01001<?php
2
3declare(strict_types=1);
4
5/**
6 * This file is part of the Carbon package.
7 *
8 * (c) Brian Nesbitt <brian@nesbot.com>
9 *
10 * For the full copyright and license information, please view the LICENSE
11 * file that was distributed with this source code.
12 */
13
14namespace Carbon\PHPStan;
15
16use Closure;
17use PHPStan\Reflection\Php\BuiltinMethodReflection;
18use PHPStan\TrinaryLogic;
19use ReflectionClass;
20use ReflectionFunction;
21use ReflectionMethod;
22use ReflectionParameter;
23use ReflectionType;
24use stdClass;
25use Throwable;
26
27abstract class AbstractMacro implements BuiltinMethodReflection
28{
29 /**
30 * The reflection function/method.
31 *
32 * @var ReflectionFunction|ReflectionMethod
33 */
34 protected $reflectionFunction;
35
36 /**
37 * The class name.
38 *
39 * @var class-string
40 */
41 private $className;
42
43 /**
44 * The method name.
45 *
46 * @var string
47 */
48 private $methodName;
49
50 /**
51 * The parameters.
52 *
53 * @var ReflectionParameter[]
54 */
55 private $parameters;
56
57 /**
58 * The is static.
59 *
60 * @var bool
61 */
62 private $static = false;
63
64 /**
65 * Macro constructor.
66 *
67 * @param string $className
68 * @phpstan-param class-string $className
69 *
70 * @param string $methodName
71 * @param callable $macro
72 */
73 public function __construct(string $className, string $methodName, $macro)
74 {
75 $this->className = $className;
76 $this->methodName = $methodName;
77 $this->reflectionFunction = \is_array($macro)
78 ? new ReflectionMethod($macro[0], $macro[1])
79 : new ReflectionFunction($macro);
80 $this->parameters = $this->reflectionFunction->getParameters();
81
82 if ($this->reflectionFunction->isClosure()) {
83 try {
84 $closure = $this->reflectionFunction->getClosure();
85 $boundClosure = Closure::bind($closure, new stdClass());
86 $this->static = (!$boundClosure || (new ReflectionFunction($boundClosure))->getClosureThis() === null);
87 } catch (Throwable $e) {
88 $this->static = true;
89 }
90 }
91 }
92
93 /**
94 * {@inheritdoc}
95 */
96 public function getDeclaringClass(): ReflectionClass
97 {
98 return new ReflectionClass($this->className);
99 }
100
101 /**
102 * {@inheritdoc}
103 */
104 public function isPrivate(): bool
105 {
106 return false;
107 }
108
109 /**
110 * {@inheritdoc}
111 */
112 public function isPublic(): bool
113 {
114 return true;
115 }
116
117 /**
118 * {@inheritdoc}
119 */
120 public function isFinal(): bool
121 {
122 return false;
123 }
124
125 /**
126 * {@inheritdoc}
127 */
128 public function isInternal(): bool
129 {
130 return false;
131 }
132
133 /**
134 * {@inheritdoc}
135 */
136 public function isAbstract(): bool
137 {
138 return false;
139 }
140
141 /**
142 * {@inheritdoc}
143 */
144 public function isStatic(): bool
145 {
146 return $this->static;
147 }
148
149 /**
150 * {@inheritdoc}
151 */
152 public function getDocComment(): ?string
153 {
154 return $this->reflectionFunction->getDocComment() ?: null;
155 }
156
157 /**
158 * {@inheritdoc}
159 */
160 public function getName(): string
161 {
162 return $this->methodName;
163 }
164
165 /**
166 * {@inheritdoc}
167 */
168 public function getParameters(): array
169 {
170 return $this->parameters;
171 }
172
173 /**
174 * {@inheritdoc}
175 */
176 public function getReturnType(): ?ReflectionType
177 {
178 return $this->reflectionFunction->getReturnType();
179 }
180
181 /**
182 * {@inheritdoc}
183 */
184 public function isDeprecated(): TrinaryLogic
185 {
186 return TrinaryLogic::createFromBoolean(
187 $this->reflectionFunction->isDeprecated() ||
188 preg_match('/@deprecated/i', $this->getDocComment() ?: '')
189 );
190 }
191
192 /**
193 * {@inheritdoc}
194 */
195 public function isVariadic(): bool
196 {
197 return $this->reflectionFunction->isVariadic();
198 }
199
200 /**
201 * {@inheritdoc}
202 */
203 public function getPrototype(): BuiltinMethodReflection
204 {
205 return $this;
206 }
207
208 /**
209 * {@inheritdoc}
210 */
211 public function getReflection(): ?ReflectionMethod
212 {
213 return $this->reflectionFunction instanceof ReflectionMethod
214 ? $this->reflectionFunction
215 : null;
216 }
217
218 public function getTentativeReturnType(): ?ReflectionType
219 {
220 return null;
221 }
222}