Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #5501 #6253

Merged
merged 4 commits into from
Aug 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/Psalm/DocComment.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,10 @@ public static function parse(string $docblock, ?int $line_number = null, bool $p
*/
public static function parsePreservingLength(\PhpParser\Comment\Doc $docblock) : ParsedDocblock
{
$parsed_docblock = \Psalm\Internal\Scanner\DocblockParser::parse($docblock->getText());
$parsed_docblock = \Psalm\Internal\Scanner\DocblockParser::parse(
$docblock->getText(),
$docblock->getStartFilePos()
);

foreach ($parsed_docblock->tags as $special_key => $_) {
if (substr($special_key, 0, 6) === 'psalm-') {
Expand Down
9 changes: 7 additions & 2 deletions src/Psalm/Internal/Analyzer/CommentAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,16 @@ public static function arrayToDocblocks(

$line_parts = self::splitDocLine($var_line);

$line_number = $comment->getStartLine() + substr_count($comment_text, "\n", 0, $offset);
$line_number = $comment->getStartLine() + substr_count(
$comment_text,
"\n",
0,
$offset - $comment->getStartFilePos()
);
$description = $parsed_docblock->description;

if ($line_parts && $line_parts[0]) {
$type_start = $offset + $comment->getStartFilePos();
$type_start = $offset;
$type_end = $type_start + strlen($line_parts[0]);

$line_parts[0] = self::sanitizeDocblockType($line_parts[0]);
Expand Down
4 changes: 2 additions & 2 deletions src/Psalm/Internal/Analyzer/StatementsAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ private static function analyzeStatement(

foreach ($suppressed as $offset => $suppress_entry) {
foreach (DocComment::parseSuppressList($suppress_entry) as $issue_offset => $issue_type) {
$new_issues[$issue_offset + $offset + $docblock->getStartFilePos()] = $issue_type;
$new_issues[$issue_offset + $offset] = $issue_type;

if ($issue_type === 'InaccessibleMethod') {
continue;
Expand All @@ -411,7 +411,7 @@ private static function analyzeStatement(
if ($codebase->track_unused_suppressions) {
IssueBuffer::addUnusedSuppression(
$statements_analyzer->getFilePath(),
$issue_offset + $offset + $docblock->getStartFilePos(),
$issue_offset + $offset,
$issue_type
);
}
Expand Down
5 changes: 4 additions & 1 deletion src/Psalm/Internal/PhpVisitor/ParamReplacementVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ public function enterNode(PhpParser\Node $node): ?int
} elseif ($node instanceof PhpParser\Node\Stmt\ClassMethod
&& ($docblock = $node->getDocComment())
) {
$parsed_docblock = \Psalm\Internal\Scanner\DocblockParser::parse($docblock->getText());
$parsed_docblock = \Psalm\Internal\Scanner\DocblockParser::parse(
$docblock->getText(),
$docblock->getStartFilePos()
);

$replaced = false;

Expand Down
59 changes: 41 additions & 18 deletions src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeDocblockParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
use Psalm\Internal\Type\TypeTokenizer;

use function array_key_first;
use function array_merge;
use function array_shift;
use function count;
use function implode;
Expand Down Expand Up @@ -82,10 +81,16 @@ public static function parse(
$template_modifier,
implode(' ', $template_type),
false,
$offset
$offset - $comment->getStartFilePos()
];
} else {
$templates[$template_name][$source_prefix] = [$template_name, null, null, false, $offset];
$templates[$template_name][$source_prefix] = [
$template_name,
null,
null,
false,
$offset - $comment->getStartFilePos()
];
}
}
}
Expand Down Expand Up @@ -116,10 +121,16 @@ public static function parse(
$template_modifier,
implode(' ', $template_type),
true,
$offset
$offset - $comment->getStartFilePos()
];
} else {
$templates[$template_name][$source_prefix] = [$template_name, null, null, true, $offset];
$templates[$template_name][$source_prefix] = [
$template_name,
null,
null,
true,
$offset - $comment->getStartFilePos()
];
}
}
}
Expand Down Expand Up @@ -255,21 +266,24 @@ public static function parse(
if (isset($parsed_docblock->tags['psalm-suppress'])) {
foreach ($parsed_docblock->tags['psalm-suppress'] as $offset => $suppress_entry) {
foreach (DocComment::parseSuppressList($suppress_entry) as $issue_offset => $suppressed_issue) {
$info->suppressed_issues[$issue_offset + $offset + $comment->getStartFilePos()] = $suppressed_issue;
$info->suppressed_issues[$issue_offset + $offset] = $suppressed_issue;
}
}
}

$imported_types = array_merge(
$parsed_docblock->tags['phpstan-import-type'] ?? [],
$parsed_docblock->tags['psalm-import-type'] ?? []
);
$imported_types = ($parsed_docblock->tags['phpstan-import-type'] ?? []) +
($parsed_docblock->tags['psalm-import-type'] ?? []);
orklah marked this conversation as resolved.
Show resolved Hide resolved

foreach ($imported_types as $offset => $imported_type_entry) {
$info->imported_types[] = [
'line_number' => $comment->getStartLine() + substr_count($comment->getText(), "\n", 0, $offset),
'start_offset' => $comment->getStartFilePos() + $offset,
'end_offset' => $comment->getStartFilePos() + $offset + strlen($imported_type_entry),
'line_number' => $comment->getStartLine() + substr_count(
$comment->getText(),
"\n",
0,
$offset - $comment->getStartFilePos()
),
'start_offset' => $offset,
'end_offset' => $offset + strlen($imported_type_entry),
'parts' => CommentAnalyzer::splitDocLine($imported_type_entry) ?: []
];
}
Expand Down Expand Up @@ -428,7 +442,12 @@ public static function parse(
$statements[0]->stmts[0]->setDocComment(
new \PhpParser\Comment\Doc(
$doc_comment->getText(),
$comment->getStartLine() + substr_count($comment->getText(), "\n", 0, $offset),
$comment->getStartLine() + substr_count(
$comment->getText(),
"\n",
0,
$offset - $comment->getStartFilePos()
),
$node_doc_comment->getStartFilePos()
)
);
Expand Down Expand Up @@ -487,8 +506,7 @@ protected static function addMagicPropertyToInfo(

$line_parts[1] = preg_replace('/,$/', '', $line_parts[1]);

$start = $offset + $comment->getStartFilePos();
$end = $start + strlen($line_parts[0]);
$end = $offset + strlen($line_parts[0]);

$line_parts[0] = str_replace("\n", '', preg_replace('@^[ \t]*\*@m', '', $line_parts[0]));

Expand All @@ -508,9 +526,14 @@ protected static function addMagicPropertyToInfo(
$info->properties[] = [
'name' => $name,
'type' => $line_parts[0],
'line_number' => $comment->getStartLine() + substr_count($comment->getText(), "\n", 0, $offset),
'line_number' => $comment->getStartLine() + substr_count(
$comment->getText(),
"\n",
0,
$offset - $comment->getStartFilePos()
),
'tag' => $property_tag,
'start' => $start,
'start' => $offset,
'end' => $end,
];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ public static function parse(PhpParser\Comment\Doc $comment): FunctionDocblockCo

$line_parts[1] = preg_replace('/,$/', '', $line_parts[1]);

$start = $offset + $comment->getStartFilePos();
$end = $start + strlen($line_parts[0]);
$end = $offset + strlen($line_parts[0]);

$line_parts[0] = CommentAnalyzer::sanitizeDocblockType($line_parts[0]);

Expand All @@ -82,8 +81,13 @@ public static function parse(PhpParser\Comment\Doc $comment): FunctionDocblockCo
$info_param = [
'name' => trim($line_parts[1]),
'type' => $line_parts[0],
'line_number' => $comment->getStartLine() + substr_count($comment_text, "\n", 0, $offset),
'start' => $start,
'line_number' => $comment->getStartLine() + substr_count(
$comment_text,
"\n",
0,
$offset - $comment->getStartFilePos()
),
'start' => $offset,
'end' => $end,
];

Expand Down Expand Up @@ -137,7 +141,12 @@ public static function parse(PhpParser\Comment\Doc $comment): FunctionDocblockCo
$info->params_out[] = [
'name' => trim($line_parts[1]),
'type' => str_replace("\n", '', $line_parts[0]),
'line_number' => $comment->getStartLine() + substr_count($comment_text, "\n", 0, $offset),
'line_number' => $comment->getStartLine() + substr_count(
$comment_text,
"\n",
0,
$offset - $comment->getStartFilePos()
),
];
}
} else {
Expand All @@ -155,7 +164,12 @@ public static function parse(PhpParser\Comment\Doc $comment): FunctionDocblockCo

$info->self_out = [
'type' => str_replace("\n", '', $line_parts[0]),
'line_number' => $comment->getStartLine() + substr_count($comment_text, "\n", 0, $offset),
'line_number' => $comment->getStartLine() + substr_count(
$comment_text,
"\n",
0,
$offset - $comment->getStartFilePos()
),
];
}
}
Expand Down Expand Up @@ -289,7 +303,12 @@ public static function parse(PhpParser\Comment\Doc $comment): FunctionDocblockCo
$info->globals[] = [
'name' => $line_parts[1],
'type' => $line_parts[0],
'line_number' => $comment->getStartLine() + substr_count($comment_text, "\n", 0, $offset),
'line_number' => $comment->getStartLine() + substr_count(
$comment_text,
"\n",
0,
$offset - $comment->getStartFilePos()
),
];
}
} else {
Expand Down Expand Up @@ -330,7 +349,7 @@ public static function parse(PhpParser\Comment\Doc $comment): FunctionDocblockCo
if (isset($parsed_docblock->tags['psalm-suppress'])) {
foreach ($parsed_docblock->tags['psalm-suppress'] as $offset => $suppress_entry) {
foreach (DocComment::parseSuppressList($suppress_entry) as $issue_offset => $suppressed_issue) {
$info->suppressed_issues[$issue_offset + $offset + $comment->getStartFilePos()] = $suppressed_issue;
$info->suppressed_issues[$issue_offset + $offset] = $suppressed_issue;
}
}
}
Expand All @@ -345,8 +364,13 @@ public static function parse(PhpParser\Comment\Doc $comment): FunctionDocblockCo

$info->throws[] = [
$throws_class,
$offset + $comment->getStartFilePos(),
$comment->getStartLine() + substr_count($comment->getText(), "\n", 0, $offset)
$offset,
$comment->getStartLine() + substr_count(
$comment->getText(),
"\n",
0,
$offset - $comment->getStartFilePos()
)
];
}
}
Expand Down Expand Up @@ -517,17 +541,21 @@ private static function extractReturnType(
throw new IncorrectDocblockException('Misplaced variable');
}

$start = $offset + $comment->getStartFilePos();
$end = $start + strlen($line_parts[0]);
$end = $offset + strlen($line_parts[0]);

$line_parts[0] = CommentAnalyzer::sanitizeDocblockType($line_parts[0]);

$info->return_type = array_shift($line_parts);
$info->return_type_description = $line_parts ? implode(' ', $line_parts) : null;

$info->return_type_line_number
= $comment->getStartLine() + substr_count($comment->getText(), "\n", 0, $offset);
$info->return_type_start = $start;
= $comment->getStartLine() + substr_count(
$comment->getText(),
"\n",
0,
$offset - $comment->getStartFilePos()
);
$info->return_type_start = $offset;
$info->return_type_end = $end;
} else {
throw new DocblockParseException('Badly-formatted @return type');
Expand Down Expand Up @@ -612,6 +640,11 @@ private static function checkUnexpectedTags(

private static function docblockLineNumber(PhpParser\Comment\Doc $comment, int $offset): int
{
return $comment->getStartLine() + substr_count($comment->getText(), "\n", 0, $offset);
return $comment->getStartLine() + substr_count(
$comment->getText(),
"\n",
0,
$offset - $comment->getStartFilePos()
);
}
}
11 changes: 9 additions & 2 deletions src/Psalm/Internal/Scanner/DocblockParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,16 @@

use const PREG_OFFSET_CAPTURE;

/**
* This class will parse Docblocks in order to extract known tags from them
*/
class DocblockParser
{
public static function parse(string $docblock) : ParsedDocblock
/**
* $offsetStart is the absolute position of the docblock in the file. It'll be used to add to the position of some
* special tags (like `psalm-suppress`) for future uses
*/
public static function parse(string $docblock, int $offsetStart) : ParsedDocblock
orklah marked this conversation as resolved.
Show resolved Hide resolved
{
// Strip off comments.
$docblock = trim($docblock);
Expand Down Expand Up @@ -89,7 +96,7 @@ public static function parse(string $docblock) : ParsedDocblock

$data_offset += $line_offset;

$special[$type][$data_offset + 3] = $data;
$special[$type][$data_offset + 3 + $offsetStart] = $data;

unset($lines[$k]);
} else {
Expand Down
23 changes: 23 additions & 0 deletions tests/AnnotationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1267,6 +1267,29 @@ function foo(string $class): Foo {
return $instance;
}',
],
'suppressNonInvariantDocblockPropertyType' => [
'<?php
class Vendor
{
/**
* @var array
*/
public array $config = [];
public function getConfig(): array {return $this->config;}
}

class A extends Vendor
{
/**
* @var string[]
* @psalm-suppress NonInvariantDocblockPropertyType
*/
public array $config = [];
}
$a = new Vendor();
$_b = new A();
echo (string)($a->getConfig()[0]??"");'
],
];
}

Expand Down