Skip to content

Commit ea34bea

Browse files
committed
Don't parse invalid doccomments
1 parent e76dadc commit ea34bea

File tree

5 files changed

+114
-64
lines changed

5 files changed

+114
-64
lines changed

SlevomatCodingStandard/Helpers/AnnotationHelper.php

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,15 @@ static function () use ($phpcsFile, $docCommentOpenPointer, $name): array {
6868
} else {
6969
$parsedDocComment = DocCommentHelper::parseDocComment($phpcsFile, $docCommentOpenPointer);
7070

71-
foreach ($parsedDocComment->getNode()->getTags() as $node) {
72-
$annotationStartPointer = self::getStartPointer($phpcsFile, $parsedDocComment->getOpenPointer(), $node);
73-
$annotations[] = new Annotation(
74-
$node,
75-
$annotationStartPointer,
76-
self::getEndPointer($phpcsFile, $parsedDocComment, $annotationStartPointer, $node)
77-
);
71+
if ($parsedDocComment !== null) {
72+
foreach ($parsedDocComment->getNode()->getTags() as $node) {
73+
$annotationStartPointer = self::getStartPointer($phpcsFile, $parsedDocComment->getOpenPointer(), $node);
74+
$annotations[] = new Annotation(
75+
$node,
76+
$annotationStartPointer,
77+
self::getEndPointer($phpcsFile, $parsedDocComment, $annotationStartPointer, $node)
78+
);
79+
}
7880
}
7981
}
8082

SlevomatCodingStandard/Helpers/DocCommentHelper.php

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PHP_CodeSniffer\Files\File;
66
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
77
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTextNode;
8+
use PHPStan\PhpDocParser\Parser\ParserException;
89
use PHPStan\PhpDocParser\Parser\TokenIterator;
910
use function array_merge;
1011
use function count;
@@ -124,6 +125,10 @@ public static function hasInheritdocAnnotation(File $phpcsFile, int $pointer): b
124125

125126
$parsedDocComment = self::parseDocComment($phpcsFile, $docCommentOpenPointer);
126127

128+
if ($parsedDocComment === null) {
129+
return false;
130+
}
131+
127132
foreach ($parsedDocComment->getNode()->children as $child) {
128133
if ($child instanceof PhpDocTextNode && strtolower($child->text) === '{@inheritdoc}') {
129134
return true;
@@ -227,6 +232,10 @@ public static function isInline(File $phpcsFile, int $docCommentOpenPointer): bo
227232

228233
$parsedDocComment = self::parseDocComment($phpcsFile, $docCommentOpenPointer);
229234

235+
if ($parsedDocComment === null) {
236+
return false;
237+
}
238+
230239
foreach ($parsedDocComment->getNode()->getTags() as $annotation) {
231240
if (preg_match('~^@(?:(?:phpstan|psalm)-)?var~i', $annotation->name) === 1) {
232241
return true;
@@ -236,24 +245,28 @@ public static function isInline(File $phpcsFile, int $docCommentOpenPointer): bo
236245
return false;
237246
}
238247

239-
public static function parseDocComment(File $phpcsFile, int $docCommentOpenPointer): ParsedDocComment
248+
public static function parseDocComment(File $phpcsFile, int $docCommentOpenPointer): ?ParsedDocComment
240249
{
241250
return SniffLocalCache::getAndSetIfNotCached(
242251
$phpcsFile,
243252
sprintf('parsed-doc-comment-%d', $docCommentOpenPointer),
244-
static function () use ($phpcsFile, $docCommentOpenPointer): ParsedDocComment {
253+
static function () use ($phpcsFile, $docCommentOpenPointer): ?ParsedDocComment {
245254
$docComment = self::getDocComment($phpcsFile, $docCommentOpenPointer);
246255

247256
$docCommentTokens = new TokenIterator(PhpDocParserHelper::getLexer()->tokenize($docComment));
248257

249-
$parsedDocComment = PhpDocParserHelper::getParser()->parse($docCommentTokens);
250-
251-
return new ParsedDocComment(
252-
$docCommentOpenPointer,
253-
$phpcsFile->getTokens()[$docCommentOpenPointer]['comment_closer'],
254-
$parsedDocComment,
255-
$docCommentTokens
256-
);
258+
try {
259+
$parsedDocComment = PhpDocParserHelper::getParser()->parse($docCommentTokens);
260+
261+
return new ParsedDocComment(
262+
$docCommentOpenPointer,
263+
$phpcsFile->getTokens()[$docCommentOpenPointer]['comment_closer'],
264+
$parsedDocComment,
265+
$docCommentTokens
266+
);
267+
} catch (ParserException $e) {
268+
return null;
269+
}
257270
}
258271
);
259272
}

SlevomatCodingStandard/Sniffs/Namespaces/ReferenceUsedNamesOnlySniff.php

Lines changed: 50 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -708,58 +708,61 @@ private function getReferences(File $phpcsFile, int $openTagPointer): array
708708
}
709709

710710
$parsedDocComment = DocCommentHelper::parseDocComment($phpcsFile, $docCommentOpenPointer);
711-
$annotations = AnnotationHelper::getAnnotations($phpcsFile, $docCommentOpenPointer);
712711

713-
foreach ($annotations as $annotation) {
714-
/** @var list<IdentifierTypeNode> $identifierTypeNodes */
715-
$identifierTypeNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), IdentifierTypeNode::class);
712+
if ($parsedDocComment !== null) {
713+
$annotations = AnnotationHelper::getAnnotations($phpcsFile, $docCommentOpenPointer);
716714

717-
foreach ($identifierTypeNodes as $typeHintNode) {
718-
$typeHint = $typeHintNode->name;
715+
foreach ($annotations as $annotation) {
716+
/** @var list<IdentifierTypeNode> $identifierTypeNodes */
717+
$identifierTypeNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), IdentifierTypeNode::class);
719718

720-
$lowercasedTypeHint = strtolower($typeHint);
721-
if (
722-
TypeHintHelper::isSimpleTypeHint($lowercasedTypeHint)
723-
|| TypeHintHelper::isSimpleUnofficialTypeHints($lowercasedTypeHint)
724-
|| !TypeHelper::isTypeName($typeHint)
725-
) {
726-
continue;
727-
}
719+
foreach ($identifierTypeNodes as $typeHintNode) {
720+
$typeHint = $typeHintNode->name;
728721

729-
$reference = new stdClass();
730-
$reference->source = self::SOURCE_ANNOTATION;
731-
$reference->parsedDocComment = $parsedDocComment;
732-
$reference->annotation = $annotation;
733-
$reference->nameNode = $typeHintNode;
734-
$reference->name = $typeHint;
735-
$reference->type = ReferencedName::TYPE_CLASS;
736-
$reference->startPointer = $annotation->getStartPointer();
737-
$reference->endPointer = null;
738-
$reference->isClass = true;
739-
$reference->isConstant = false;
740-
$reference->isFunction = false;
741-
742-
$references[] = $reference;
743-
}
722+
$lowercasedTypeHint = strtolower($typeHint);
723+
if (
724+
TypeHintHelper::isSimpleTypeHint($lowercasedTypeHint)
725+
|| TypeHintHelper::isSimpleUnofficialTypeHints($lowercasedTypeHint)
726+
|| !TypeHelper::isTypeName($typeHint)
727+
) {
728+
continue;
729+
}
730+
731+
$reference = new stdClass();
732+
$reference->source = self::SOURCE_ANNOTATION;
733+
$reference->parsedDocComment = $parsedDocComment;
734+
$reference->annotation = $annotation;
735+
$reference->nameNode = $typeHintNode;
736+
$reference->name = $typeHint;
737+
$reference->type = ReferencedName::TYPE_CLASS;
738+
$reference->startPointer = $annotation->getStartPointer();
739+
$reference->endPointer = null;
740+
$reference->isClass = true;
741+
$reference->isConstant = false;
742+
$reference->isFunction = false;
743+
744+
$references[] = $reference;
745+
}
744746

745-
/** @var list<ConstFetchNode> $constantFetchNodes */
746-
$constantFetchNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), ConstFetchNode::class);
747-
748-
foreach ($constantFetchNodes as $constantFetchNode) {
749-
$reference = new stdClass();
750-
$reference->source = self::SOURCE_ANNOTATION_CONSTANT_FETCH;
751-
$reference->parsedDocComment = $parsedDocComment;
752-
$reference->annotation = $annotation;
753-
$reference->constantFetchNode = $constantFetchNode;
754-
$reference->name = $constantFetchNode->className;
755-
$reference->type = ReferencedName::TYPE_CLASS;
756-
$reference->startPointer = $annotation->getStartPointer();
757-
$reference->endPointer = null;
758-
$reference->isClass = true;
759-
$reference->isConstant = false;
760-
$reference->isFunction = false;
761-
762-
$references[] = $reference;
747+
/** @var list<ConstFetchNode> $constantFetchNodes */
748+
$constantFetchNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), ConstFetchNode::class);
749+
750+
foreach ($constantFetchNodes as $constantFetchNode) {
751+
$reference = new stdClass();
752+
$reference->source = self::SOURCE_ANNOTATION_CONSTANT_FETCH;
753+
$reference->parsedDocComment = $parsedDocComment;
754+
$reference->annotation = $annotation;
755+
$reference->constantFetchNode = $constantFetchNode;
756+
$reference->name = $constantFetchNode->className;
757+
$reference->type = ReferencedName::TYPE_CLASS;
758+
$reference->startPointer = $annotation->getStartPointer();
759+
$reference->endPointer = null;
760+
$reference->isClass = true;
761+
$reference->isConstant = false;
762+
$reference->isFunction = false;
763+
764+
$references[] = $reference;
765+
}
763766
}
764767
}
765768

tests/Helpers/DocCommentHelperTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,26 @@ public function testIsInline(): void
391391
}
392392
}
393393

394+
public function testIsInlineWithInvalidDocComment(): void
395+
{
396+
self::assertFalse(
397+
DocCommentHelper::isInline(
398+
$this->getTestedCodeSnifferFile(),
399+
$this->findPointerByLineAndType($this->getTestedCodeSnifferFile(), 135, T_DOC_COMMENT_OPEN_TAG)
400+
)
401+
);
402+
}
403+
404+
public function testHasInheritdocAnnotationWithInvalidDocComment(): void
405+
{
406+
self::assertFalse(
407+
DocCommentHelper::hasInheritdocAnnotation(
408+
$this->getTestedCodeSnifferFile(),
409+
$this->findPointerByLineAndType($this->getTestedCodeSnifferFile(), 129, T_DOC_COMMENT_OPEN_TAG)
410+
)
411+
);
412+
}
413+
394414
private function getTestedCodeSnifferFile(): File
395415
{
396416
if ($this->testedCodeSnifferFile === null) {

tests/Helpers/data/docComment.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,15 @@ class ClassWithAttribute
125125
class ClassWithAttributes
126126
{
127127
}
128+
129+
/**** Invalid doccomment *****/
130+
class WithInvalidDocComment
131+
{
132+
133+
public function __construct()
134+
{
135+
/**** Invalid doccomment *****/
136+
$var = 'var';
137+
}
138+
139+
}

0 commit comments

Comments
 (0)