Skip to content

Commit af1f618

Browse files
committed
Support for offset access type syntax in annotations
1 parent 0b2f104 commit af1f618

11 files changed

+146
-4
lines changed

SlevomatCodingStandard/Helpers/AnnotationTypeHelper.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
1919
use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode;
2020
use PHPStan\PhpDocParser\Ast\Type\NullableTypeNode;
21+
use PHPStan\PhpDocParser\Ast\Type\OffsetAccessTypeNode;
2122
use PHPStan\PhpDocParser\Ast\Type\ThisTypeNode;
2223
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
2324
use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode;
@@ -104,6 +105,13 @@ public static function getIdentifierTypeNodes(TypeNode $typeNode): array
104105
);
105106
}
106107

108+
if ($typeNode instanceof OffsetAccessTypeNode) {
109+
return array_merge(
110+
self::getIdentifierTypeNodes($typeNode->type),
111+
self::getIdentifierTypeNodes($typeNode->offset)
112+
);
113+
}
114+
107115
/** @var IdentifierTypeNode|ThisTypeNode $typeNode */
108116
$typeNode = $typeNode;
109117
return [$typeNode];
@@ -174,6 +182,13 @@ public static function getConstantTypeNodes(TypeNode $typeNode): array
174182
);
175183
}
176184

185+
if ($typeNode instanceof OffsetAccessTypeNode) {
186+
return array_merge(
187+
self::getConstantTypeNodes($typeNode->type),
188+
self::getConstantTypeNodes($typeNode->offset)
189+
);
190+
}
191+
177192
if (!$typeNode instanceof ConstTypeNode) {
178193
return [];
179194
}
@@ -247,6 +262,13 @@ public static function getUnionTypeNodes(TypeNode $typeNode): array
247262
);
248263
}
249264

265+
if ($typeNode instanceof OffsetAccessTypeNode) {
266+
return array_merge(
267+
self::getUnionTypeNodes($typeNode->type),
268+
self::getUnionTypeNodes($typeNode->offset)
269+
);
270+
}
271+
250272
return [];
251273
}
252274

@@ -315,6 +337,13 @@ public static function getArrayTypeNodes(TypeNode $typeNode): array
315337
);
316338
}
317339

340+
if ($typeNode instanceof OffsetAccessTypeNode) {
341+
return array_merge(
342+
self::getArrayTypeNodes($typeNode->type),
343+
self::getArrayTypeNodes($typeNode->offset)
344+
);
345+
}
346+
318347
return [];
319348
}
320349

@@ -447,6 +476,13 @@ public static function change(TypeNode $masterTypeNode, TypeNode $typeNodeToChan
447476
);
448477
}
449478

479+
if ($masterTypeNode instanceof OffsetAccessTypeNode) {
480+
return new OffsetAccessTypeNode(
481+
self::change($masterTypeNode->type, $typeNodeToChange, $changedTypeNode),
482+
self::change($masterTypeNode->offset, $typeNodeToChange, $changedTypeNode)
483+
);
484+
}
485+
450486
return clone $masterTypeNode;
451487
}
452488

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"require": {
1818
"php": "^7.2 || ^8.0",
1919
"dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7",
20-
"phpstan/phpdoc-parser": "^1.4.1",
20+
"phpstan/phpdoc-parser": "^1.5.1",
2121
"squizlabs/php_codesniffer": "^3.6.2"
2222
},
2323
"require-dev": {

tests/Sniffs/Namespaces/ReferenceUsedNamesOnlySniffTest.php

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,7 @@ public function testSearchingInAnnotations(): void
725725
]
726726
);
727727

728-
self::assertSame(44, $report->getErrorCount());
728+
self::assertSame(50, $report->getErrorCount());
729729

730730
self::assertSniffError(
731731
$report,
@@ -984,6 +984,43 @@ public function testSearchingInAnnotations(): void
984984
'Class \Foo\Conditional10 should not be referenced via a fully qualified name, but via a use statement.'
985985
);
986986

987+
self::assertSniffError(
988+
$report,
989+
172,
990+
ReferenceUsedNamesOnlySniff::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME,
991+
'Class \Foo\OffsetAccessType should not be referenced via a fully qualified name, but via a use statement.'
992+
);
993+
self::assertSniffError(
994+
$report,
995+
172,
996+
ReferenceUsedNamesOnlySniff::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME,
997+
'Class \Foo\OffsetAccessOffset should not be referenced via a fully qualified name, but via a use statement.'
998+
);
999+
self::assertSniffError(
1000+
$report,
1001+
172,
1002+
ReferenceUsedNamesOnlySniff::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME,
1003+
'Class \Foo\OffsetAccessType2 should not be referenced via a fully qualified name, but via a use statement.'
1004+
);
1005+
self::assertSniffError(
1006+
$report,
1007+
172,
1008+
ReferenceUsedNamesOnlySniff::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME,
1009+
'Class \Foo\OffsetAccessOffset2 should not be referenced via a fully qualified name, but via a use statement.'
1010+
);
1011+
self::assertSniffError(
1012+
$report,
1013+
172,
1014+
ReferenceUsedNamesOnlySniff::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME,
1015+
'Class \Foo\OffsetAccessType3 should not be referenced via a fully qualified name, but via a use statement.'
1016+
);
1017+
self::assertSniffError(
1018+
$report,
1019+
172,
1020+
ReferenceUsedNamesOnlySniff::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME,
1021+
'Class \Foo\OffsetAccessOffset3 should not be referenced via a fully qualified name, but via a use statement.'
1022+
);
1023+
9871024
self::assertAllFixedInFile($report);
9881025
}
9891026

tests/Sniffs/Namespaces/data/shouldBeInUseStatementSearchingInAnnotations.fixed.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818
use Foo\Conditional8;
1919
use Foo\Conditional9;
2020
use Foo\Conditional10;
21+
use Foo\OffsetAccessType;
22+
use Foo\OffsetAccessOffset;
23+
use Foo\OffsetAccessType2;
24+
use Foo\OffsetAccessOffset2;
25+
use Foo\OffsetAccessType3;
26+
use Foo\OffsetAccessOffset3;
2127

2228
/**
2329
* @method \DateTimeImmutable|int|DateTime getProperty()
@@ -178,3 +184,14 @@ public function withConditionalParameter($parameter)
178184
}
179185

180186
}
187+
188+
class OffsetAccess
189+
{
190+
191+
/**
192+
* @return OffsetAccessType[OffsetAccessOffset]|OffsetAccessType2[OffsetAccessOffset2]|OffsetAccessType3[array{offset: OffsetAccessOffset3}]
193+
*/
194+
public function returnOffsetAccess()
195+
{}
196+
197+
}

tests/Sniffs/Namespaces/data/shouldBeInUseStatementSearchingInAnnotations.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,14 @@ public function withConditionalParameter($parameter)
164164
}
165165

166166
}
167+
168+
class OffsetAccess
169+
{
170+
171+
/**
172+
* @return \Foo\OffsetAccessType[\Foo\OffsetAccessOffset]|\Foo\OffsetAccessType2[\Foo\OffsetAccessOffset2]|\Foo\OffsetAccessType3[array{offset: \Foo\OffsetAccessOffset3}]
173+
*/
174+
public function returnOffsetAccess()
175+
{}
176+
177+
}

tests/Sniffs/TypeHints/DisallowArrayTypeHintSyntaxSniffTest.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public function testErrors(): void
2222
],
2323
]);
2424

25-
self::assertSame(29, $report->getErrorCount());
25+
self::assertSame(30, $report->getErrorCount());
2626

2727
self::assertSniffError(
2828
$report,
@@ -199,6 +199,13 @@ public function testErrors(): void
199199
'Usage of array type hint syntax in "float[]" is disallowed, use generic type hint syntax instead.'
200200
);
201201

202+
self::assertSniffError(
203+
$report,
204+
94,
205+
DisallowArrayTypeHintSyntaxSniff::CODE_DISALLOWED_ARRAY_TYPE_HINT_SYNTAX,
206+
'Usage of array type hint syntax in "string[]" is disallowed, use generic type hint syntax instead.'
207+
);
208+
202209
self::assertAllFixedInFile($report);
203210
}
204211

tests/Sniffs/TypeHints/NullTypeHintOnLastPositionSniffTest.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public function testErrors(): void
1717
{
1818
$report = self::checkFile(__DIR__ . '/data/nullTypeHintOnLastPositionErrors.php');
1919

20-
self::assertSame(27, $report->getErrorCount());
20+
self::assertSame(28, $report->getErrorCount());
2121

2222
self::assertSniffError($report, 7, NullTypeHintOnLastPositionSniff::CODE_NULL_TYPE_HINT_NOT_ON_LAST_POSITION);
2323
self::assertSniffError($report, 11, NullTypeHintOnLastPositionSniff::CODE_NULL_TYPE_HINT_NOT_ON_LAST_POSITION);
@@ -79,6 +79,8 @@ public function testErrors(): void
7979
self::assertSniffError($report, 111, NullTypeHintOnLastPositionSniff::CODE_NULL_TYPE_HINT_NOT_ON_LAST_POSITION);
8080
self::assertSniffError($report, 118, NullTypeHintOnLastPositionSniff::CODE_NULL_TYPE_HINT_NOT_ON_LAST_POSITION);
8181

82+
self::assertSniffError($report, 130, NullTypeHintOnLastPositionSniff::CODE_NULL_TYPE_HINT_NOT_ON_LAST_POSITION);
83+
8284
self::assertAllFixedInFile($report);
8385
}
8486

tests/Sniffs/TypeHints/data/disallowArrayTypeHintSyntaxErrors.fixed.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,9 @@ public function u($parameter)
9191
{
9292
}
9393

94+
/** @return OffsetAccess[array<string>] */
95+
public function v($parameter)
96+
{
97+
}
98+
9499
}

tests/Sniffs/TypeHints/data/disallowArrayTypeHintSyntaxErrors.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,9 @@ public function u($parameter)
9191
{
9292
}
9393

94+
/** @return OffsetAccess[string[]] */
95+
public function v($parameter)
96+
{
97+
}
98+
9499
}

tests/Sniffs/TypeHints/data/nullTypeHintOnLastPositionErrors.fixed.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,14 @@ public function withConditionalParameter($parameter)
122122
}
123123

124124
}
125+
126+
class OffsetAccess
127+
{
128+
129+
/**
130+
* @return \Foo\OffsetAccessType[(\Foo\OffsetAccessOffset2|null)]
131+
*/
132+
public function returnOffsetAccess()
133+
{}
134+
135+
}

0 commit comments

Comments
 (0)