Skip to content

Commit b80f463

Browse files
committed
Help psalm to detect enum varaiables and avoid the More/LessSpecificReturn exceptions
1 parent d24d4db commit b80f463

File tree

330 files changed

+2963
-3055
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

330 files changed

+2963
-3055
lines changed

psalm.baseline.xml

Lines changed: 0 additions & 232 deletions
Original file line numberDiff line numberDiff line change
@@ -88,186 +88,6 @@
8888
<code>getRows</code>
8989
</PossiblyNullReference>
9090
</file>
91-
<file src="src/Service/CloudFormation/src/Result/DescribeStacksOutput.php">
92-
<LessSpecificReturnStatement>
93-
<code>$items</code>
94-
</LessSpecificReturnStatement>
95-
<MoreSpecificReturnType>
96-
<code><![CDATA[list<Capability::*>]]></code>
97-
</MoreSpecificReturnType>
98-
</file>
99-
<file src="src/Service/CodeBuild/src/Result/BatchGetBuildsOutput.php">
100-
<LessSpecificReturnStatement>
101-
<code>$items</code>
102-
</LessSpecificReturnStatement>
103-
<MoreSpecificReturnType>
104-
<code><![CDATA[list<CacheMode::*>]]></code>
105-
</MoreSpecificReturnType>
106-
</file>
107-
<file src="src/Service/CodeBuild/src/Result/StartBuildOutput.php">
108-
<LessSpecificReturnStatement>
109-
<code>$items</code>
110-
</LessSpecificReturnStatement>
111-
<MoreSpecificReturnType>
112-
<code><![CDATA[list<CacheMode::*>]]></code>
113-
</MoreSpecificReturnType>
114-
</file>
115-
<file src="src/Service/CodeBuild/src/Result/StopBuildOutput.php">
116-
<LessSpecificReturnStatement>
117-
<code>$items</code>
118-
</LessSpecificReturnStatement>
119-
<MoreSpecificReturnType>
120-
<code><![CDATA[list<CacheMode::*>]]></code>
121-
</MoreSpecificReturnType>
122-
</file>
123-
<file src="src/Service/CodeDeploy/src/Result/GetDeploymentOutput.php">
124-
<LessSpecificReturnStatement>
125-
<code>$items</code>
126-
</LessSpecificReturnStatement>
127-
<MoreSpecificReturnType>
128-
<code><![CDATA[list<AutoRollbackEvent::*>]]></code>
129-
</MoreSpecificReturnType>
130-
</file>
131-
<file src="src/Service/Kinesis/src/Result/DescribeStreamOutput.php">
132-
<LessSpecificReturnStatement>
133-
<code>$items</code>
134-
</LessSpecificReturnStatement>
135-
<MoreSpecificReturnType>
136-
<code><![CDATA[list<MetricsName::*>]]></code>
137-
</MoreSpecificReturnType>
138-
</file>
139-
<file src="src/Service/Kinesis/src/Result/DescribeStreamSummaryOutput.php">
140-
<LessSpecificReturnStatement>
141-
<code>$items</code>
142-
</LessSpecificReturnStatement>
143-
<MoreSpecificReturnType>
144-
<code><![CDATA[list<MetricsName::*>]]></code>
145-
</MoreSpecificReturnType>
146-
</file>
147-
<file src="src/Service/Kinesis/src/Result/EnhancedMonitoringOutput.php">
148-
<LessSpecificReturnStatement>
149-
<code>$items</code>
150-
</LessSpecificReturnStatement>
151-
<MoreSpecificReturnType>
152-
<code><![CDATA[list<MetricsName::*>]]></code>
153-
</MoreSpecificReturnType>
154-
</file>
155-
<file src="src/Service/Kms/src/Result/CreateKeyResponse.php">
156-
<LessSpecificReturnStatement>
157-
<code>$items</code>
158-
<code>$items</code>
159-
<code>$items</code>
160-
<code>$items</code>
161-
</LessSpecificReturnStatement>
162-
<MoreSpecificReturnType>
163-
<code><![CDATA[list<EncryptionAlgorithmSpec::*>]]></code>
164-
<code><![CDATA[list<MacAlgorithmSpec::*>]]></code>
165-
<code><![CDATA[list<SigningAlgorithmSpec::*>]]></code>
166-
<code><![CDATA[list<KeyAgreementAlgorithmSpec::*>]]></code>
167-
</MoreSpecificReturnType>
168-
</file>
169-
<file src="src/Service/Lambda/src/Result/ListFunctionsResponse.php">
170-
<LessSpecificReturnStatement>
171-
<code>$items</code>
172-
</LessSpecificReturnStatement>
173-
<MoreSpecificReturnType>
174-
<code><![CDATA[list<Architecture::*>]]></code>
175-
</MoreSpecificReturnType>
176-
</file>
177-
<file src="src/Service/Lambda/src/Result/ListLayerVersionsResponse.php">
178-
<LessSpecificReturnStatement>
179-
<code>$items</code>
180-
<code>$items</code>
181-
</LessSpecificReturnStatement>
182-
<MoreSpecificReturnType>
183-
<code><![CDATA[list<Architecture::*>]]></code>
184-
<code><![CDATA[list<Runtime::*>]]></code>
185-
</MoreSpecificReturnType>
186-
</file>
187-
<file src="src/Service/Lambda/src/Result/ListVersionsByFunctionResponse.php">
188-
<LessSpecificReturnStatement>
189-
<code>$items</code>
190-
</LessSpecificReturnStatement>
191-
<MoreSpecificReturnType>
192-
<code><![CDATA[list<Architecture::*>]]></code>
193-
</MoreSpecificReturnType>
194-
</file>
195-
<file src="src/Service/Lambda/src/Result/PublishLayerVersionResponse.php">
196-
<LessSpecificReturnStatement>
197-
<code>$items</code>
198-
<code>$items</code>
199-
</LessSpecificReturnStatement>
200-
<MoreSpecificReturnType>
201-
<code><![CDATA[list<Architecture::*>]]></code>
202-
<code><![CDATA[list<Runtime::*>]]></code>
203-
</MoreSpecificReturnType>
204-
</file>
205-
<file src="src/Service/MediaConvert/src/Result/CreateJobResponse.php">
206-
<LessSpecificReturnStatement>
207-
<code>$items</code>
208-
<code>$items</code>
209-
<code>$items</code>
210-
<code>$items</code>
211-
</LessSpecificReturnStatement>
212-
<MoreSpecificReturnType>
213-
<code><![CDATA[list<AudioChannelTag::*>]]></code>
214-
<code><![CDATA[list<HlsAdMarkers::*>]]></code>
215-
<code><![CDATA[list<TeletextPageType::*>]]></code>
216-
<code><![CDATA[list<FrameMetricType::*>]]></code>
217-
</MoreSpecificReturnType>
218-
</file>
219-
<file src="src/Service/MediaConvert/src/Result/GetJobResponse.php">
220-
<LessSpecificReturnStatement>
221-
<code>$items</code>
222-
<code>$items</code>
223-
<code>$items</code>
224-
<code>$items</code>
225-
</LessSpecificReturnStatement>
226-
<MoreSpecificReturnType>
227-
<code><![CDATA[list<AudioChannelTag::*>]]></code>
228-
<code><![CDATA[list<HlsAdMarkers::*>]]></code>
229-
<code><![CDATA[list<TeletextPageType::*>]]></code>
230-
<code><![CDATA[list<FrameMetricType::*>]]></code>
231-
</MoreSpecificReturnType>
232-
</file>
233-
<file src="src/Service/MediaConvert/src/Result/ListJobsResponse.php">
234-
<LessSpecificReturnStatement>
235-
<code>$items</code>
236-
<code>$items</code>
237-
<code>$items</code>
238-
<code>$items</code>
239-
</LessSpecificReturnStatement>
240-
<MoreSpecificReturnType>
241-
<code><![CDATA[list<AudioChannelTag::*>]]></code>
242-
<code><![CDATA[list<HlsAdMarkers::*>]]></code>
243-
<code><![CDATA[list<TeletextPageType::*>]]></code>
244-
<code><![CDATA[list<FrameMetricType::*>]]></code>
245-
</MoreSpecificReturnType>
246-
</file>
247-
<file src="src/Service/Rekognition/src/Result/IndexFacesResponse.php">
248-
<LessSpecificReturnStatement>
249-
<code>$items</code>
250-
</LessSpecificReturnStatement>
251-
<MoreSpecificReturnType>
252-
<code><![CDATA[list<Reason::*>]]></code>
253-
</MoreSpecificReturnType>
254-
</file>
255-
<file src="src/Service/S3/src/Result/ListObjectsV2Output.php">
256-
<LessSpecificReturnStatement>
257-
<code>$items</code>
258-
</LessSpecificReturnStatement>
259-
<MoreSpecificReturnType>
260-
<code><![CDATA[list<ChecksumAlgorithm::*>]]></code>
261-
</MoreSpecificReturnType>
262-
</file>
263-
<file src="src/Service/S3/src/Result/ListObjectVersionsOutput.php">
264-
<LessSpecificReturnStatement>
265-
<code>$items</code>
266-
</LessSpecificReturnStatement>
267-
<MoreSpecificReturnType>
268-
<code><![CDATA[list<ChecksumAlgorithm::*>]]></code>
269-
</MoreSpecificReturnType>
270-
</file>
27191
<file src="src/Service/S3/src/Signer/SignerV4ForS3.php">
27292
<InvalidArgument>
27393
<code>array_keys($s3SignerOptions)</code>
@@ -289,56 +109,4 @@
289109
<code><![CDATA[$d = \DateTimeImmutable::createFromFormat('U.u', \sprintf('%.6F', $data['stopDate']))]]></code>
290110
</PossiblyFalsePropertyAssignmentValue>
291111
</file>
292-
<file src="src/Service/Sqs/src/Result/GetQueueAttributesResult.php">
293-
<LessSpecificReturnStatement>
294-
<code>$items</code>
295-
</LessSpecificReturnStatement>
296-
<MoreSpecificReturnType>
297-
<code><![CDATA[array<QueueAttributeName::*, string>]]></code>
298-
</MoreSpecificReturnType>
299-
</file>
300-
<file src="src/Service/Sqs/src/Result/ReceiveMessageResult.php">
301-
<LessSpecificReturnStatement>
302-
<code>$items</code>
303-
</LessSpecificReturnStatement>
304-
<MoreSpecificReturnType>
305-
<code><![CDATA[array<MessageSystemAttributeName::*, string>]]></code>
306-
</MoreSpecificReturnType>
307-
</file>
308-
<file src="src/Service/Lambda/src/Result/FunctionConfiguration.php">
309-
<LessSpecificReturnStatement>
310-
<code><![CDATA[$items]]></code>
311-
</LessSpecificReturnStatement>
312-
<MoreSpecificReturnType>
313-
<code><![CDATA[list<Architecture::*>]]></code>
314-
</MoreSpecificReturnType>
315-
</file>
316-
<file src="src/Service/CognitoIdentityProvider/src/Result/InitiateAuthResponse.php">
317-
<LessSpecificReturnStatement>
318-
<code><![CDATA[$items]]></code>
319-
</LessSpecificReturnStatement>
320-
<MoreSpecificReturnType>
321-
<code><![CDATA[list<ChallengeNameType::*>]]></code>
322-
</MoreSpecificReturnType>
323-
</file>
324-
<file src="src/Service/CognitoIdentityProvider/src/Result/AdminInitiateAuthResponse.php">
325-
<LessSpecificReturnStatement>
326-
<code><![CDATA[$items]]></code>
327-
</LessSpecificReturnStatement>
328-
<MoreSpecificReturnType>
329-
<code><![CDATA[list<ChallengeNameType::*>]]></code>
330-
</MoreSpecificReturnType>
331-
</file>
332-
<file src="src/Service/Kms/src/Result/GetPublicKeyResponse.php">
333-
<LessSpecificReturnStatement>
334-
<code><![CDATA[$items]]></code>
335-
<code><![CDATA[$items]]></code>
336-
<code><![CDATA[$items]]></code>
337-
</LessSpecificReturnStatement>
338-
<MoreSpecificReturnType>
339-
<code><![CDATA[list<EncryptionAlgorithmSpec::*>]]></code>
340-
<code><![CDATA[list<KeyAgreementAlgorithmSpec::*>]]></code>
341-
<code><![CDATA[list<SigningAlgorithmSpec::*>]]></code>
342-
</MoreSpecificReturnType>
343-
</file>
344112
</files>

src/CodeGenerator/src/Generator/CodeGenerator/PopulatorGenerator.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ private function generateProperties(StructureShape $shape, ClassBuilder $classBu
9090
if (null !== $propertyDocumentation = $memberShape->getDocumentationMember()) {
9191
$property->setComment(GeneratorHelper::parseDocumentation($propertyDocumentation));
9292
}
93-
[$returnType, $parameterType, $memberClassNames] = $this->typeGenerator->getPhpType($memberShape);
93+
[$returnType, $parameterType, $memberClassNames] = $this->typeGenerator->getPhpType($memberShape, false);
9494
foreach ($memberClassNames as $memberClassName) {
9595
$classBuilder->addUse($memberClassName->getFqdn());
9696
}
@@ -100,7 +100,7 @@ private function generateProperties(StructureShape $shape, ClassBuilder $classBu
100100
}
101101

102102
if ($memberShape instanceof StructureShape) {
103-
$this->objectGenerator->generate($memberShape);
103+
$this->objectGenerator->generate($memberShape, false, false);
104104
} elseif ($memberShape instanceof MapShape) {
105105
$mapKeyShape = $memberShape->getKey()->getShape();
106106
if ('string' !== $mapKeyShape->getType()) {
@@ -111,7 +111,7 @@ private function generateProperties(StructureShape $shape, ClassBuilder $classBu
111111
}
112112

113113
if (($valueShape = $memberShape->getValue()->getShape()) instanceof StructureShape) {
114-
$this->objectGenerator->generate($valueShape);
114+
$this->objectGenerator->generate($valueShape, false, false);
115115
}
116116
if (!empty($valueShape->getEnum())) {
117117
$this->enumGenerator->generate($valueShape);
@@ -299,7 +299,7 @@ private function generatePopulator(Operation $operation, StructureShape $shape,
299299
private function generateListShapeMemberShape(Shape $memberShape, bool $forEndpoint): void
300300
{
301301
if ($memberShape instanceof StructureShape) {
302-
$this->objectGenerator->generate($memberShape, $forEndpoint);
302+
$this->objectGenerator->generate($memberShape, $forEndpoint, false);
303303
} elseif ($memberShape instanceof ListShape) {
304304
$this->generateListShapeMemberShape($memberShape->getMember()->getShape(), $forEndpoint);
305305
}

src/CodeGenerator/src/Generator/CodeGenerator/TypeGenerator.php

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public function __construct(NamespaceRegistry $namespaceRegistry)
3939
*
4040
* @return array{string, ClassName[]} [docblock representation, ClassName related]
4141
*/
42-
public function generateDocblock(StructureShape $shape, ClassName $shapeClassName, bool $alternateClass = true, bool $allNullable = false, bool $isObject = false, array $extra = []): array
42+
public function generateDocblock(StructureShape $shape, ClassName $shapeClassName, bool $alternateClass = true, bool $allNullable = false, bool $isObject = false, array $extra = [], bool $strictEnum = true): array
4343
{
4444
$classNames = [];
4545
if ($alternateClass) {
@@ -67,7 +67,11 @@ public function generateDocblock(StructureShape $shape, ClassName $shapeClassNam
6767
$param = 'array<' . $className->getName() . '|array>';
6868
} elseif (!empty($listMemberShape->getEnum())) {
6969
$classNames[] = $className = $this->namespaceRegistry->getEnum($listMemberShape);
70-
$param = 'array<' . $className->getName() . '::*>';
70+
if ($strictEnum) {
71+
$param = 'array<' . $className->getName() . '::*>';
72+
} else {
73+
$param = 'array<' . $className->getName() . '::*|string>';
74+
}
7175
} else {
7276
$param = $this->getNativePhpType($listMemberShape->getType()) . '[]';
7377
}
@@ -81,13 +85,20 @@ public function generateDocblock(StructureShape $shape, ClassName $shapeClassNam
8185
} elseif (!empty($mapValueShape->getEnum())) {
8286
$classNames[] = $className = $this->namespaceRegistry->getEnum($mapValueShape);
8387
$param = $className->getName() . '::*';
88+
if (!$strictEnum) {
89+
$param .= '|string';
90+
}
8491
} else {
8592
$param = $this->getNativePhpType($mapValueShape->getType());
8693
}
8794
$mapKeyShape = $memberShape->getKey()->getShape();
8895
if (!empty($mapKeyShape->getEnum())) {
8996
$classNames[] = $className = $this->namespaceRegistry->getEnum($mapKeyShape);
90-
$param = 'array<' . $className->getName() . '::*, ' . $param . '>';
97+
if ($strictEnum) {
98+
$param = 'array<' . $className->getName() . '::*, ' . $param . '>';
99+
} else {
100+
$param = 'array<' . $className->getName() . '::*|string, ' . $param . '>';
101+
}
91102
} else {
92103
$param = 'array<string, ' . $param . '>';
93104
}
@@ -101,6 +112,9 @@ public function generateDocblock(StructureShape $shape, ClassName $shapeClassNam
101112
if (!empty($memberShape->getEnum())) {
102113
$classNames[] = $className = $this->namespaceRegistry->getEnum($memberShape);
103114
$param = $className->getName() . '::*';
115+
if (!$strictEnum) {
116+
$param .= '|string';
117+
}
104118
} else {
105119
$param = $this->getNativePhpType($memberShape->getType());
106120
}
@@ -136,7 +150,7 @@ public function generateDocblock(StructureShape $shape, ClassName $shapeClassNam
136150
*
137151
* @return array{string, string, ClassName[]} [typeHint value, docblock representation, ClassName related]
138152
*/
139-
public function getPhpType(Shape $shape): array
153+
public function getPhpType(Shape $shape, bool $strictEnum = true): array
140154
{
141155
$memberClassNames = [];
142156
if ($shape instanceof StructureShape) {
@@ -147,8 +161,8 @@ public function getPhpType(Shape $shape): array
147161

148162
if ($shape instanceof ListShape) {
149163
$listMemberShape = $shape->getMember()->getShape();
150-
[$type, $doc, $memberClassNames] = $this->getPhpType($listMemberShape);
151-
if ('::*' === substr($doc, -3)) {
164+
[$type, $doc, $memberClassNames] = $this->getPhpType($listMemberShape, $strictEnum);
165+
if (!empty($listMemberShape->getEnum())) {
152166
$doc = "list<$doc>";
153167
} else {
154168
$doc .= '[]';
@@ -160,10 +174,14 @@ public function getPhpType(Shape $shape): array
160174
if ($shape instanceof MapShape) {
161175
$mapKeyShape = $shape->getKey()->getShape();
162176
$mapValueShape = $shape->getValue()->getShape();
163-
[$type, $doc, $memberClassNames] = $this->getPhpType($mapValueShape);
177+
[$type, $doc, $memberClassNames] = $this->getPhpType($mapValueShape, $strictEnum);
164178
if (!empty($mapKeyShape->getEnum())) {
165179
$memberClassNames[] = $memberClassName = $this->namespaceRegistry->getEnum($mapKeyShape);
166-
$doc = "array<{$memberClassName->getName()}::*, $doc>";
180+
if ($strictEnum) {
181+
$doc = "array<{$memberClassName->getName()}::*, $doc>";
182+
} else {
183+
$doc = "array<{$memberClassName->getName()}::*|string, $doc>";
184+
}
167185
} else {
168186
$doc = "array<string, $doc>";
169187
}
@@ -180,6 +198,9 @@ public function getPhpType(Shape $shape): array
180198
$memberClassNames[] = $memberClassName = $this->namespaceRegistry->getEnum($shape);
181199

182200
$doc = $memberClassName->getName() . '::*';
201+
if (!$strictEnum) {
202+
$doc .= '|string';
203+
}
183204
}
184205

185206
return [$type, $doc, $memberClassNames];

0 commit comments

Comments
 (0)