Skip to content

Commit

Permalink
Add hook for plugins after FunctionLikeAnalysis (#3258)
Browse files Browse the repository at this point in the history
  • Loading branch information
orklah committed Apr 28, 2020
1 parent a0667f1 commit 8571746
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/running_psalm/plugins/authoring_plugins.md
Expand Up @@ -19,6 +19,7 @@ class SomePlugin implements \Psalm\Plugin\Hook\AfterStatementAnalysisInterface
- `AfterEveryFunctionCallAnalysisInterface` - called after Psalm evaluates any function call. Cannot influence the call further.
- `AfterExpressionAnalysisInterface` - called after Psalm evaluates an expression.
- `AfterFunctionCallAnalysisInterface` - called after Psalm evaluates a function call to any function defined within the project itself. Can alter the return type or perform modifications of the call.
- `AfterFunctionLikeAnalysisInterface` - called after Psalm has completed its analysis of a given function-like.
- `AfterMethodCallAnalysisInterface` - called after Psalm analyzes a method call.
- `AfterStatementAnalysisInterface` - called after Psalm evaluates an statement.
- `FunctionExistenceProviderInterface` - can be used to override Psalm's builtin function existence checks for one or more functions.
Expand Down
7 changes: 7 additions & 0 deletions src/Psalm/Config.php
Expand Up @@ -496,6 +496,13 @@ class Config
*/
public $before_analyze_file = [];

/**
* Static methods to be called after functionlike checks have completed
*
* @var class-string<Hook\AfterFunctionLikeAnalysisInterface>[]
*/
public $after_functionlike_checks = [];

/** @var array<string, mixed> */
private $predefined_constants;

Expand Down
25 changes: 25 additions & 0 deletions src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php
Expand Up @@ -766,6 +766,31 @@ function (FunctionLikeParameter $p) {
}
}

$plugin_classes = $codebase->config->after_functionlike_checks;

if ($plugin_classes) {
$file_manipulations = [];

foreach ($plugin_classes as $plugin_fq_class_name) {
if ($plugin_fq_class_name::afterStatementAnalysis(
$this->function,
$storage,
$this,
$codebase,
$file_manipulations
) === false) {
return false;
}
}

if ($file_manipulations) {
\Psalm\Internal\FileManipulation\FileManipulationBuffer::add(
$this->getFilePath(),
$file_manipulations
);
}
}

return null;
}

Expand Down
26 changes: 26 additions & 0 deletions src/Psalm/Plugin/Hook/AfterFunctionLikeAnalysisInterface.php
@@ -0,0 +1,26 @@
<?php
namespace Psalm\Plugin\Hook;

use PhpParser\Node;
use Psalm\Codebase;
use Psalm\FileManipulation;
use Psalm\StatementsSource;
use Psalm\Storage\FunctionLikeStorage;

interface AfterFunctionLikeAnalysisInterface
{
/**
* Called after a statement has been checked
*
* @param FileManipulation[] $file_replacements
*
* @return null|false
*/
public static function afterStatementAnalysis(
Node\FunctionLike $stmt,
FunctionLikeStorage $classlike_storage,
StatementsSource $statements_source,
Codebase $codebase,
array &$file_replacements = []
);
}
4 changes: 4 additions & 0 deletions src/Psalm/PluginRegistrationSocket.php
Expand Up @@ -121,5 +121,9 @@ public function registerHooksFromClass(string $handler)
if (is_subclass_of($handler, Hook\StringInterpreterInterface::class)) {
$this->config->string_interpreters[$handler] = $handler;
}

if (is_subclass_of($handler, Hook\AfterFunctionLikeAnalysisInterface::class)) {
$this->config->after_functionlike_checks[$handler] = $handler;
}
}
}

0 comments on commit 8571746

Please sign in to comment.