mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 20:34:47 +01:00
Add error message when psalter asked to work beyond its abilities; allow fixing all issues and output list of fixable issues (#1687)
* Oputput error message when asked to fix non-fixable issue * Document ability to fix function PossiblyUndefinedGlobalVariable * Add --issues=all option to fix all possible issues * Add --list-supported-issues option to psalter * Fix psalm issues * Add newline to end of psalter help output * Adjust messages output from psalter * Use fwrite(STDERR, instead of die( for issue list related errors in psalter * Restore missing exits in psalter
This commit is contained in:
parent
5861476765
commit
04ef20da1f
@ -36,7 +36,8 @@ The above example plugin converts all unnecessarily qualified classnames in your
|
||||
|
||||
## Supported fixes
|
||||
|
||||
This initial release provides support for the following alterations, corresponding to the names of issues Psalm finds:
|
||||
This initial release provides support for the following alterations, corresponding to the names of issues Psalm finds.
|
||||
To fix all of these at once, run `vendor/bin/psalter --issues=all`
|
||||
|
||||
### MissingReturnType
|
||||
|
||||
@ -252,6 +253,34 @@ function foo() : string {
|
||||
|
||||
Running `vendor/bin/psalter --issues=PossiblyUndefinedVariable` on
|
||||
|
||||
```php
|
||||
function foo()
|
||||
{
|
||||
if (rand(0, 1)) {
|
||||
$a = 5;
|
||||
}
|
||||
echo $a;
|
||||
}
|
||||
```
|
||||
|
||||
gives
|
||||
|
||||
```php
|
||||
function foo()
|
||||
{
|
||||
$a = null;
|
||||
if (rand(0, 1)) {
|
||||
$a = 5;
|
||||
}
|
||||
echo $a;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### PossiblyUndefinedGlobalVariable
|
||||
|
||||
Running `vendor/bin/psalter --issues=PossiblyUndefinedGlobalVariable` on
|
||||
|
||||
```php
|
||||
if (rand(0, 1)) {
|
||||
$a = 5;
|
||||
|
8
src/Psalm/Exception/UnsupportedIssueToFixException.php
Normal file
8
src/Psalm/Exception/UnsupportedIssueToFixException.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Psalm\Exception;
|
||||
|
||||
class UnsupportedIssueToFixException extends \Exception
|
||||
{
|
||||
|
||||
}
|
@ -4,15 +4,32 @@ namespace Psalm\Internal\Analyzer;
|
||||
use Psalm\Codebase;
|
||||
use Psalm\Config;
|
||||
use Psalm\Context;
|
||||
use Psalm\Exception\UnsupportedIssueToFixException;
|
||||
use Psalm\Internal\LanguageServer\{LanguageServer, ProtocolStreamReader, ProtocolStreamWriter};
|
||||
use Psalm\Internal\Provider\ClassLikeStorageProvider;
|
||||
use Psalm\Internal\Provider\FileProvider;
|
||||
use Psalm\Internal\Provider\FileReferenceProvider;
|
||||
use Psalm\Internal\Provider\ParserCacheProvider;
|
||||
use Psalm\Internal\Provider\Providers;
|
||||
use Psalm\Issue\InvalidFalsableReturnType;
|
||||
use Psalm\Issue\InvalidNullableReturnType;
|
||||
use Psalm\Issue\InvalidReturnType;
|
||||
use Psalm\Issue\LessSpecificReturnType;
|
||||
use Psalm\Issue\MismatchingDocblockParamType;
|
||||
use Psalm\Issue\MismatchingDocblockReturnType;
|
||||
use Psalm\Issue\MissingClosureReturnType;
|
||||
use Psalm\Issue\MissingParamType;
|
||||
use Psalm\Issue\MissingReturnType;
|
||||
use Psalm\Issue\PossiblyUndefinedGlobalVariable;
|
||||
use Psalm\Issue\PossiblyUndefinedVariable;
|
||||
use Psalm\Issue\PossiblyUnusedMethod;
|
||||
use Psalm\Issue\PossiblyUnusedProperty;
|
||||
use Psalm\Issue\UnusedMethod;
|
||||
use Psalm\Issue\UnusedProperty;
|
||||
use Psalm\Progress\Progress;
|
||||
use Psalm\Progress\VoidProgress;
|
||||
use Psalm\Type;
|
||||
use Psalm\Issue\CodeIssue;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@ -156,6 +173,27 @@ class ProjectAnalyzer
|
||||
self::TYPE_TEXT,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array<int, class-string<CodeIssue>>
|
||||
*/
|
||||
const SUPPORTED_ISSUES_TO_FIX = [
|
||||
InvalidFalsableReturnType::class,
|
||||
InvalidNullableReturnType::class,
|
||||
InvalidReturnType::class,
|
||||
LessSpecificReturnType::class,
|
||||
MismatchingDocblockParamType::class,
|
||||
MismatchingDocblockReturnType::class,
|
||||
MissingClosureReturnType::class,
|
||||
MissingParamType::class,
|
||||
MissingReturnType::class,
|
||||
PossiblyUndefinedGlobalVariable::class,
|
||||
PossiblyUndefinedVariable::class,
|
||||
PossiblyUnusedMethod::class,
|
||||
PossiblyUnusedProperty::class,
|
||||
UnusedMethod::class,
|
||||
UnusedProperty::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @param bool $use_color
|
||||
* @param bool $show_info
|
||||
@ -795,14 +833,34 @@ class ProjectAnalyzer
|
||||
|
||||
/**
|
||||
* @param array<string, bool> $issues
|
||||
* @throws UnsupportedIssueToFixException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setIssuesToFix(array $issues)
|
||||
{
|
||||
$supported_issues_to_fix = static::getSupportedIssuesToFix();
|
||||
|
||||
$unsupportedIssues = array_diff(array_keys($issues), $supported_issues_to_fix);
|
||||
|
||||
if (! empty($unsupportedIssues)) {
|
||||
throw new UnsupportedIssueToFixException(
|
||||
'Psalm doesn\'t know how to fix issue(s): ' . implode(', ', $unsupportedIssues) . PHP_EOL
|
||||
. 'Supported issues to fix are: ' . implode(',', $supported_issues_to_fix)
|
||||
);
|
||||
}
|
||||
|
||||
$this->issues_to_fix = $issues;
|
||||
}
|
||||
|
||||
public function setAllIssuesToFix(): void
|
||||
{
|
||||
/** @var array<string, true> $keyed_issues */
|
||||
$keyed_issues = array_fill_keys(static::getSupportedIssuesToFix(), true);
|
||||
|
||||
$this->setIssuesToFix($keyed_issues);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, bool>
|
||||
*
|
||||
@ -954,4 +1012,19 @@ class ProjectAnalyzer
|
||||
|
||||
throw new \LogicException('failed to detect number of CPUs!');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string>
|
||||
*/
|
||||
public static function getSupportedIssuesToFix(): array
|
||||
{
|
||||
return array_map(
|
||||
/** @param class-string $issue_class */
|
||||
function (string $issue_class): string {
|
||||
$parts = explode('\\', $issue_class);
|
||||
return end($parts);
|
||||
},
|
||||
self::SUPPORTED_ISSUES_TO_FIX
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ $args = array_slice($argv, 1);
|
||||
$valid_short_options = ['f:', 'm', 'h', 'r:'];
|
||||
$valid_long_options = [
|
||||
'help', 'debug', 'debug-by-line', 'config:', 'file:', 'root:',
|
||||
'plugin:', 'issues:', 'php-version:', 'dry-run', 'safe-types',
|
||||
'plugin:', 'issues:', 'list-supported-issues', 'php-version:', 'dry-run', 'safe-types',
|
||||
'find-unused-code', 'threads:', 'codeowner:',
|
||||
'allow-backwards-incompatible-changes:',
|
||||
];
|
||||
@ -116,7 +116,11 @@ Options:
|
||||
--php-version=PHP_MAJOR_VERSION.PHP_MINOR_VERSION
|
||||
|
||||
--issues=IssueType1,IssueType2
|
||||
If any issues can be fixed automatically, Psalm will update the codebase
|
||||
If any issues can be fixed automatically, Psalm will update the codebase. To fix as many issues as possible,
|
||||
use --issues=all
|
||||
|
||||
--list-supported-issues
|
||||
Display the list of issues that psalter knows how to fix
|
||||
|
||||
--find-unused-code
|
||||
Include unused code as a candidate for removal
|
||||
@ -129,14 +133,19 @@ Options:
|
||||
|
||||
--allow-backwards-incompatible-changes=BOOL
|
||||
Allow Psalm modify method signatures that could break code outside the project. Defaults to true.
|
||||
|
||||
HELP;
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!isset($options['issues']) && (!isset($options['plugin']) || $options['plugin'] === false)) {
|
||||
die('Please specify the issues you want to fix with --issues=IssueOne,IssueTwo '
|
||||
. 'or provide a plugin that has its own manipulations with --plugin=path/to/plugin.php' . PHP_EOL);
|
||||
if (!isset($options['issues']) &&
|
||||
!isset($options['list-supported-issues']) &&
|
||||
(!isset($options['plugin']) || $options['plugin'] === false)
|
||||
) {
|
||||
fwrite(STDERR, 'Please specify the issues you want to fix with --issues=IssueOne,IssueTwo or --issues=all, ' .
|
||||
'or provide a plugin that has its own manipulations with --plugin=path/to/plugin.php' . PHP_EOL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (isset($options['root'])) {
|
||||
@ -189,6 +198,11 @@ $providers = new Psalm\Internal\Provider\Providers(
|
||||
new Psalm\Internal\Provider\ClassLikeStorageCacheProvider($config)
|
||||
);
|
||||
|
||||
if (array_key_exists('list-supported-issues', $options)) {
|
||||
echo implode(',', ProjectAnalyzer::getSupportedIssuesToFix()) . PHP_EOL;
|
||||
exit();
|
||||
}
|
||||
|
||||
$debug = array_key_exists('debug', $options);
|
||||
$progress = $debug
|
||||
? new DebugProgress()
|
||||
@ -373,7 +387,17 @@ $project_analyzer->alterCodeAfterCompletion(
|
||||
array_key_exists('dry-run', $options),
|
||||
array_key_exists('safe-types', $options)
|
||||
);
|
||||
$project_analyzer->setIssuesToFix($keyed_issues);
|
||||
|
||||
if ($keyed_issues === ['all' => true]) {
|
||||
$project_analyzer->setAllIssuesToFix();
|
||||
} else {
|
||||
try {
|
||||
$project_analyzer->setIssuesToFix($keyed_issues);
|
||||
} catch (\Psalm\Exception\UnsupportedIssueToFixException $e) {
|
||||
fwrite(STDERR, $e->getMessage() . PHP_EOL);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
$start_time = microtime(true);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user