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

Allow suppressing UnusedPsalmSuppress, remove unused suppressions. #7133

Merged
merged 3 commits into from Dec 11, 2021
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions psalm.xml.dist
Expand Up @@ -16,6 +16,7 @@
xsi:schemaLocation="https://getpsalm.org/schema/config config.xsd"
limitMethodComplexity="true"
errorBaseline="psalm-baseline.xml"
findUnusedPsalmSuppress="true"
>
<stubs>
<file name="stubs/phpparser.phpstub"/>
Expand Down
3 changes: 0 additions & 3 deletions src/Psalm/CodeLocation.php
Expand Up @@ -137,9 +137,6 @@ public function setCommentLine(int $line): void
$this->docblock_line_number = $line;
}

/**
* @psalm-suppress MixedArrayAccess
*/
private function calculateRealLocation(): void
{
if ($this->have_recalculated) {
Expand Down
7 changes: 0 additions & 7 deletions src/Psalm/Config.php
Expand Up @@ -850,7 +850,6 @@ private static function processConfigDeprecations(
/**
* @psalm-suppress MixedMethodCall
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedOperand
* @psalm-suppress MixedArgument
* @psalm-suppress MixedPropertyFetch
*
Expand Down Expand Up @@ -1294,8 +1293,6 @@ public function getPluginClasses(): array

/**
* Initialises all the plugins (done once the config is fully loaded)
*
* @psalm-suppress MixedAssignment
*/
public function initializePlugins(ProjectAnalyzer $project_analyzer): void
{
Expand Down Expand Up @@ -2065,10 +2062,6 @@ public function setIncludeCollector(IncludeCollector $include_collector): void
$this->include_collector = $include_collector;
}

/**
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
*/
public function visitComposerAutoloadFiles(ProjectAnalyzer $project_analyzer, ?Progress $progress = null): void
{
if ($progress === null) {
Expand Down
1 change: 0 additions & 1 deletion src/Psalm/Config/Creator.php
Expand Up @@ -208,7 +208,6 @@ public static function getPaths(string $current_dir, ?string $suggested_dir): ar
* @return list<string>
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArgument
* @psalm-suppress PossiblyUndefinedArrayOffset
*/
private static function getPsr4Or0Paths(string $current_dir, array $composer_json): array
{
Expand Down
3 changes: 0 additions & 3 deletions src/Psalm/FileBasedPluginAdapter.php
Expand Up @@ -36,9 +36,6 @@ public function __construct(string $path, Config $config, Codebase $codebase)
$this->codebase = $codebase;
}

/**
* @psalm-suppress PossiblyUnusedParam
*/
public function __invoke(RegistrationInterface $registration, ?SimpleXMLElement $config = null): void
{
$fq_class_name = $this->getPluginClassForPath($this->path);
Expand Down
Expand Up @@ -67,7 +67,6 @@ class ReturnTypeAnalyzer
* @return false|null
*
* @psalm-suppress PossiblyUnusedReturnValue unused but seems important
* @psalm-suppress ComplexMethod to be refactored
*/
public static function verifyReturnType(
FunctionLike $function,
Expand Down
9 changes: 7 additions & 2 deletions src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php
Expand Up @@ -56,6 +56,7 @@
use function array_values;
use function count;
use function end;
use function in_array;
use function is_string;
use function md5;
use function microtime;
Expand Down Expand Up @@ -186,8 +187,12 @@ public function analyze(
$project_analyzer = $this->getProjectAnalyzer();

if ($codebase->track_unused_suppressions && !isset($storage->suppressed_issues[0])) {
foreach ($storage->suppressed_issues as $offset => $issue_name) {
IssueBuffer::addUnusedSuppression($this->getFilePath(), $offset, $issue_name);
if (count($storage->suppressed_issues) === 1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mind explaining what this condition does?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's there so /** @psalm-suppress UnusedPsalmSuppress */ still shows up as an unused suppression. I could have done array_values($storage->suppressed_issues) === ["UnusedPsalmSuppress"] but I figured this is both faster, shorter, and allows other cases to early out as well. Should I add a comment there so it's a bit more obvious?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! Yes please, it wasn't immediately obvious to me and I had the context :p

But yeah, I see what this does now, thanks!

|| !in_array("UnusedPsalmSuppress", $storage->suppressed_issues)
) {
foreach ($storage->suppressed_issues as $offset => $issue_name) {
IssueBuffer::addUnusedSuppression($this->getFilePath(), $offset, $issue_name);
}
}
}

Expand Down
Expand Up @@ -695,7 +695,6 @@ private static function handleUnpackedArray(
$array_creation_info->property_types[$new_offset] = $property_value;
}
} elseif ($unpacked_atomic_type instanceof Type\Atomic\TArray) {
/** @psalm-suppress PossiblyUndefinedArrayOffset provably true, but Psalm can’t see it */
if ($unpacked_atomic_type->type_params[1]->isEmpty()) {
continue;
}
Expand Down
20 changes: 13 additions & 7 deletions src/Psalm/Internal/Analyzer/StatementsAnalyzer.php
Expand Up @@ -57,8 +57,10 @@
use function array_keys;
use function array_merge;
use function array_search;
use function count;
use function fwrite;
use function get_class;
use function in_array;
use function is_string;
use function preg_split;
use function reset;
Expand Down Expand Up @@ -420,18 +422,22 @@ 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] = $issue_type;
}
}

if ($codebase->track_unused_suppressions
&& (count($new_issues) === 1) || !in_array("UnusedPsalmSuppress", $new_issues)
) {
foreach ($new_issues as $offset => $issue_type) {
if ($issue_type === 'InaccessibleMethod') {
continue;
}

if ($codebase->track_unused_suppressions) {
IssueBuffer::addUnusedSuppression(
$statements_analyzer->getFilePath(),
$issue_offset + $offset,
$issue_type
);
}
IssueBuffer::addUnusedSuppression(
$statements_analyzer->getFilePath(),
$offset,
$issue_type
);
}
}

Expand Down
3 changes: 0 additions & 3 deletions src/Psalm/Internal/CliUtils.php
Expand Up @@ -58,7 +58,6 @@ public static function requireAutoloaders(

$psalm_dir = dirname(__DIR__, 3);

/** @psalm-suppress UndefinedConstant */
$in_phar = Phar::running() || strpos(__NAMESPACE__, 'HumbugBox');

if ($in_phar) {
Expand Down Expand Up @@ -154,9 +153,7 @@ public static function requireAutoloaders(
}

/**
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedAssignment
* @psalm-suppress PossiblyUndefinedStringArrayOffset
*/
public static function getVendorDir(string $current_dir): string
{
Expand Down
4 changes: 0 additions & 4 deletions src/Psalm/Internal/Codebase/InternalCallMapHandler.php
Expand Up @@ -338,9 +338,6 @@ public static function getCallablesFromCallMap(string $function_id): ?array
* Gets the method/function call map
*
* @return array<string, array<int|string, string>>
* @psalm-suppress MixedInferredReturnType as the use of require buggers things up
* @psalm-suppress MixedReturnStatement
* @psalm-suppress MixedReturnTypeCoercion
*/
public static function getCallMap(): array
{
Expand Down Expand Up @@ -397,7 +394,6 @@ public static function getCallMap(): array
* }>,
* removed: array<string, array<int|string, string>>
* }
* @psalm-suppress UnresolvableInclude
*/
$diff_call_map = require($delta_file);

Expand Down
3 changes: 0 additions & 3 deletions src/Psalm/Internal/Codebase/Reflection.php
Expand Up @@ -422,9 +422,6 @@ public static function getPsalmTypeFromReflectionType(?ReflectionType $reflectio
return Type::getMixed();
}

/**
* @psalm-suppress UndefinedClass,TypeDoesNotContainType
*/
if ($reflection_type instanceof ReflectionNamedType) {
$type = $reflection_type->getName();
} elseif ($reflection_type instanceof ReflectionUnionType) {
Expand Down
12 changes: 9 additions & 3 deletions src/Psalm/Internal/Fork/Pool.php
Expand Up @@ -368,7 +368,9 @@ private function readResultsFromChildren(): array
// Kill all children
foreach ($this->child_pid_list as $child_pid) {
/**
* @psalm-suppress UndefinedConstant - does not exist on windows
* SIGTERM does not exist on windows
* @psalm-suppress UnusedPsalmSuppress
* @psalm-suppress UndefinedConstant
* @psalm-suppress MixedArgument
*/
posix_kill($child_pid, SIGTERM);
Expand Down Expand Up @@ -422,7 +424,9 @@ public function wait(): array

if ($process_lookup) {
/**
* @psalm-suppress UndefinedConstant - does not exist on windows
* SIGALRM does not exist on windows
* @psalm-suppress UnusedPsalmSuppress
* @psalm-suppress UndefinedConstant
* @psalm-suppress MixedArgument
*/
posix_kill($child_pid, SIGALRM);
Expand All @@ -438,7 +442,9 @@ public function wait(): array
$term_sig = pcntl_wtermsig($status);

/**
* @psalm-suppress UndefinedConstant - does not exist on windows
* SIGALRM does not exist on windows
* @psalm-suppress UnusedPsalmSuppress
* @psalm-suppress UndefinedConstant
*/
if ($term_sig !== SIGALRM) {
$this->did_have_error = true;
Expand Down
1 change: 0 additions & 1 deletion src/Psalm/Internal/LanguageServer/LanguageServer.php
Expand Up @@ -140,7 +140,6 @@ function (Message $msg): Generator {
// Invoke the method handler to get a result
/**
* @var Promise
* @psalm-suppress UndefinedDocblockClass
*/
$dispatched = $this->dispatch($msg->body);
/** @psalm-suppress MixedAssignment */
Expand Down
4 changes: 0 additions & 4 deletions src/Psalm/Internal/LanguageServer/ProtocolStreamReader.php
Expand Up @@ -51,9 +51,6 @@ public function __construct($input)
asyncCall(
/**
* @return Generator<int, Promise<?string>, ?string, void>
* @psalm-suppress MixedReturnTypeCoercion
* @psalm-suppress MixedArgument in old Amp versions
* @psalm-suppress MixedAssignment in old Amp versions
*/
function () use ($input): Generator {
while ($this->is_accepting_new_requests) {
Expand Down Expand Up @@ -119,7 +116,6 @@ private function readMessages(string $buffer): int
$this->emit('message', [$msg]);
/**
* @psalm-suppress DocblockTypeContradiction
* @psalm-suppress RedundantConditionGivenDocblockType
*/
if (!$this->is_accepting_new_requests) {
// If we fork, don't read any bytes in the input buffer from the worker process.
Expand Down
4 changes: 0 additions & 4 deletions src/Psalm/Internal/PhpVisitor/CheckTrivialExprVisitor.php
Expand Up @@ -15,10 +15,6 @@ class CheckTrivialExprVisitor extends PhpParser\NodeVisitorAbstract

private function checkNonTrivialExpr(PhpParser\Node\Expr $node): bool
{
/**
* @psalm-suppress UndefinedClass
* @psalm-suppress TypeDoesNotContainType
*/
if ($node instanceof PhpParser\Node\Expr\ArrayDimFetch
|| $node instanceof PhpParser\Node\Expr\Closure
|| $node instanceof PhpParser\Node\Expr\ClosureUse
Expand Down
3 changes: 0 additions & 3 deletions src/Psalm/Internal/PhpVisitor/OffsetShifterVisitor.php
Expand Up @@ -54,9 +54,6 @@ public function enterNode(PhpParser\Node $node): ?int
$node->setAttribute('comments', $new_comments);
}

/**
* @psalm-suppress MixedOperand
*/
$node->setAttribute(
'startFilePos',
$attrs['startFilePos'] + $this->file_offset + ($this->extra_offsets[$attrs['startFilePos']] ?? 0)
Expand Down
Expand Up @@ -46,8 +46,6 @@ class ClassLikeDocblockParser
{
/**
* @throws DocblockParseException if there was a problem parsing the docblock
*
* @psalm-suppress MixedArrayAccess
*/
public static function parse(
Node $node,
Expand Down
3 changes: 0 additions & 3 deletions src/Psalm/Internal/Provider/FakeFileProvider.php
Expand Up @@ -49,9 +49,6 @@ public function getModifiedTime(string $file_path): int
return $this->fake_file_times[$file_path] ?? parent::getModifiedTime($file_path);
}

/**
* @psalm-suppress InvalidPropertyAssignmentValue because microtime is needed for cache busting
*/
public function registerFile(string $file_path, string $file_contents): void
{
$this->fake_files[$file_path] = $file_contents;
Expand Down
7 changes: 0 additions & 7 deletions src/Psalm/Internal/Provider/ParserCacheProvider.php
Expand Up @@ -72,8 +72,6 @@ public function __construct(Config $config, bool $use_file_cache = true)

/**
* @return list<PhpParser\Node\Stmt>|null
*
* @psalm-suppress UndefinedFunction
*/
public function loadStatementsFromCache(
string $file_path,
Expand Down Expand Up @@ -117,8 +115,6 @@ public function loadStatementsFromCache(

/**
* @return list<PhpParser\Node\Stmt>|null
*
* @psalm-suppress UndefinedFunction
*/
public function loadExistingStatementsFromCache(string $file_path): ?array
{
Expand Down Expand Up @@ -218,9 +214,6 @@ private function getExistingFileContentHashes(): array

/**
* @param list<PhpParser\Node\Stmt> $stmts
*
*
* @psalm-suppress UndefinedFunction
*/
public function saveStatementsToCache(
string $file_path,
Expand Down
1 change: 0 additions & 1 deletion src/Psalm/Internal/Provider/StatementsProvider.php
Expand Up @@ -150,7 +150,6 @@ public function getStatementsForFile(string $file_path, string $php_version, ?Pr

$existing_statements = $this->parser_cache_provider->loadExistingStatementsFromCache($file_path);

/** @psalm-suppress DocblockTypeContradiction */
if ($existing_statements && !$existing_statements[0] instanceof PhpParser\Node\Stmt) {
$existing_statements = null;
}
Expand Down
1 change: 0 additions & 1 deletion src/Psalm/Internal/Type/TypeTokenizer.php
Expand Up @@ -97,7 +97,6 @@ class TypeTokenizer
*
* @return list<array{string, int}>
*
* @psalm-suppress ComplexMethod
* @psalm-suppress PossiblyUndefinedIntArrayOffset
*/
public static function tokenize(string $string_type, bool $ignore_space = true): array
Expand Down
29 changes: 29 additions & 0 deletions tests/IssueSuppressionTest.php
Expand Up @@ -371,6 +371,24 @@ class Foo {
}
',
],
'suppressUnusedSuppression' => [
'<?php
class Foo {
/**
* @psalm-suppress UnusedPsalmSuppress, MissingPropertyType
*/
public string $bar = "baz";

/**
* @psalm-suppress UnusedPsalmSuppress, MissingReturnType
*/
public function foobar(): string
{
return "foobar";
}
}
',
],
];
}

Expand Down Expand Up @@ -408,6 +426,17 @@ public function b() {
function foo($s = Foo::BAR) : void {}',
'error_message' => 'UndefinedClass',
],
'suppressUnusedSuppressionByItselfIsNotSuppressed' => [
'<?php
class Foo {
/**
* @psalm-suppress UnusedPsalmSuppress
*/
public string $bar = "baz";
}
',
'error_message' => 'UnusedPsalmSuppress',
],
];
}
}
3 changes: 0 additions & 3 deletions tests/TestConfig.php
Expand Up @@ -15,9 +15,6 @@ class TestConfig extends Config
/** @var ProjectFileFilter|null */
private static $cached_project_files = null;

/**
* @psalm-suppress PossiblyNullPropertyAssignmentValue because cache_directory isn't strictly nullable
*/
public function __construct()
{
parent::__construct();
Expand Down