mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +01:00
Adds support for fixing missing throws doc block
This commit is contained in:
parent
50fb396bbb
commit
c6854cf567
@ -706,6 +706,10 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @var list<class-string>
|
||||
*/
|
||||
$missingThrowsDocblockErrors = [];
|
||||
foreach ($statements_analyzer->getUncaughtThrows($context) as $possibly_thrown_exception => $codelocations) {
|
||||
$is_expected = false;
|
||||
|
||||
@ -719,6 +723,7 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer
|
||||
}
|
||||
|
||||
if (!$is_expected) {
|
||||
$missingThrowsDocblockErrors[] = $possibly_thrown_exception;
|
||||
foreach ($codelocations as $codelocation) {
|
||||
// issues are suppressed in ThrowAnalyzer, CallAnalyzer, etc.
|
||||
IssueBuffer::maybeAdd(
|
||||
@ -732,6 +737,18 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
$codebase->alter_code
|
||||
&& isset($project_analyzer->getIssuesToFix()['MissingThrowsDocblock'])
|
||||
) {
|
||||
$manipulator = FunctionDocblockManipulator::getForFunction(
|
||||
$project_analyzer,
|
||||
$this->source->getFilePath(),
|
||||
$this->function
|
||||
);
|
||||
$manipulator->addThrowsDocblock($missingThrowsDocblockErrors);
|
||||
}
|
||||
|
||||
if ($codebase->taint_flow_graph
|
||||
&& $this->function instanceof ClassMethod
|
||||
&& $cased_method_id
|
||||
|
@ -1322,6 +1322,7 @@ class ProjectAnalyzer
|
||||
|
||||
$supported_issues_to_fix[] = 'MissingImmutableAnnotation';
|
||||
$supported_issues_to_fix[] = 'MissingPureAnnotation';
|
||||
$supported_issues_to_fix[] = 'MissingThrowsDocblock';
|
||||
|
||||
$unsupportedIssues = array_diff(array_keys($issues), $supported_issues_to_fix);
|
||||
|
||||
|
@ -96,6 +96,9 @@ class FunctionDocblockManipulator
|
||||
/** @var bool */
|
||||
private $is_pure = false;
|
||||
|
||||
/** @var list<class-string> */
|
||||
private $throwsExceptions = [];
|
||||
|
||||
/**
|
||||
* @param Closure|Function_|ClassMethod|ArrowFunction $stmt
|
||||
*/
|
||||
@ -395,6 +398,16 @@ class FunctionDocblockManipulator
|
||||
$modified_docblock = true;
|
||||
$parsed_docblock->tags['psalm-pure'] = [''];
|
||||
}
|
||||
if (\count($this->throwsExceptions) > 0) {
|
||||
$modified_docblock = true;
|
||||
$parsed_docblock->tags['throws'] = [
|
||||
\array_reduce(
|
||||
$this->throwsExceptions,
|
||||
fn(string $throwsClause, string $exception) => $throwsClause === '' ? $exception : $throwsClause.'|'.$exception,
|
||||
''
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
if ($this->new_phpdoc_return_type && $this->new_phpdoc_return_type !== $old_phpdoc_return_type) {
|
||||
@ -528,6 +541,14 @@ class FunctionDocblockManipulator
|
||||
$this->is_pure = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<class-string> $exceptions
|
||||
*/
|
||||
public function addThrowsDocblock(array $exceptions): void
|
||||
{
|
||||
$this->throwsExceptions = $exceptions;
|
||||
}
|
||||
|
||||
public static function clearCache(): void
|
||||
{
|
||||
self::$manipulators = [];
|
||||
|
@ -86,6 +86,7 @@ abstract class FileManipulationTestCase extends TestCase
|
||||
$safe_types
|
||||
);
|
||||
$this->project_analyzer->getCodebase()->allow_backwards_incompatible_changes = $allow_backwards_incompatible_changes;
|
||||
$this->project_analyzer->getConfig()->check_for_throws_docblock = true;
|
||||
|
||||
if (strpos(static::class, 'Unused') || strpos(static::class, 'Unnecessary')) {
|
||||
$this->project_analyzer->getCodebase()->reportUnusedCode();
|
||||
|
37
tests/FileManipulation/ThrowsBlockAdditionTest.php
Normal file
37
tests/FileManipulation/ThrowsBlockAdditionTest.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Psalm\Tests\FileManipulation;
|
||||
|
||||
class ThrowsBlockAdditionTest extends FileManipulationTestCase
|
||||
{
|
||||
/**
|
||||
* @return array<string,array{string,string,string,string[],bool}>
|
||||
*/
|
||||
public function providerValidCodeParse(): array
|
||||
{
|
||||
return [
|
||||
'addThrowsAnnotationToFunction' => [
|
||||
'<?php
|
||||
function foo(string $s): string {
|
||||
if("" === $s) {
|
||||
throw new \InvalidArgumentException();
|
||||
}
|
||||
return $s;
|
||||
}',
|
||||
'<?php
|
||||
/**
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
function foo(string $s): string {
|
||||
if("" === $s) {
|
||||
throw new \InvalidArgumentException();
|
||||
}
|
||||
return $s;
|
||||
}',
|
||||
'7.4',
|
||||
['MissingThrowsDocblock'],
|
||||
true,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user