mirror of
https://github.com/danog/psalm-not-empty.git
synced 2024-11-26 20:04:54 +01:00
first commit
This commit is contained in:
parent
84d4f2d352
commit
6013ab1fda
13
.editorconfig
Normal file
13
.editorconfig
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
charset = utf-8
|
||||||
|
|
||||||
|
|
||||||
|
[*.{yaml,yml}]
|
||||||
|
indent_size = 2
|
32
composer.json
Normal file
32
composer.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "orklah/psalm-no-empty",
|
||||||
|
"description": "Automatically change empty() into a more explicit expression",
|
||||||
|
"type": "psalm-plugin",
|
||||||
|
"minimum-stability": "dev",
|
||||||
|
"prefer-stable": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "orklah"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"extra": {
|
||||||
|
"psalm" : {
|
||||||
|
"pluginClass": "Orklah\\NotEmpty\\Plugin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.3",
|
||||||
|
"vimeo/psalm": "master"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Orklah\\NotEmpty\\": ["./src"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"nikic/php-parser": "^4.0",
|
||||||
|
"phpunit/phpunit": "^9.5",
|
||||||
|
"psalm/plugin-phpunit": "^0.15.0"
|
||||||
|
}
|
||||||
|
}
|
75
src/Hooks/NotEmptyHooks.php
Normal file
75
src/Hooks/NotEmptyHooks.php
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Orklah\NotEmpty\Hooks;
|
||||||
|
|
||||||
|
use PhpParser\Node\Expr\Empty_;
|
||||||
|
use PhpParser\Node\Expr\Variable;
|
||||||
|
use Psalm\FileManipulation;
|
||||||
|
use Psalm\Plugin\EventHandler\AfterExpressionAnalysisInterface;
|
||||||
|
use Psalm\Plugin\EventHandler\Event\AfterExpressionAnalysisEvent;
|
||||||
|
use Psalm\Type\Atomic;
|
||||||
|
use function get_class;
|
||||||
|
|
||||||
|
|
||||||
|
class NotEmptyHooks implements AfterExpressionAnalysisInterface
|
||||||
|
{
|
||||||
|
public static function afterExpressionAnalysis(AfterExpressionAnalysisEvent $event): ?bool
|
||||||
|
{
|
||||||
|
if (!$event->getCodebase()->alter_code) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$expr = $event->getExpr();
|
||||||
|
$node_provider = $event->getStatementsSource()->getNodeTypeProvider();
|
||||||
|
|
||||||
|
if (!$expr instanceof Empty_) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($expr->expr instanceof Variable) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$type = $node_provider->getType($expr->expr);
|
||||||
|
if ($type === null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type->from_docblock) {
|
||||||
|
//TODO: maybe add an issue in non alter mode
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$type->isSingle()) {
|
||||||
|
// TODO: add functionnality with isSingleAndMaybeNullable and add || EXPR !== null
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$startPos = $expr->getStartFilePos() + 1;
|
||||||
|
$endPos = $expr->getEndFilePos();
|
||||||
|
|
||||||
|
$atomic_types = $type->getAtomicTypes();
|
||||||
|
$atomic_type = array_shift($atomic_types);
|
||||||
|
$display_expr = (string)$expr->expr;
|
||||||
|
if ($atomic_type instanceof Atomic\TInt) {
|
||||||
|
$file_manipulation = new FileManipulation($startPos, $endPos, $display_expr . " === 0");
|
||||||
|
$event->setFileReplacements([$file_manipulation]);
|
||||||
|
} elseif ($atomic_type instanceof Atomic\TFloat) {
|
||||||
|
$file_manipulation = new FileManipulation($startPos, $endPos, $display_expr . " === 0.0");
|
||||||
|
$event->setFileReplacements([$file_manipulation]);
|
||||||
|
} elseif ($atomic_type instanceof Atomic\TString) {
|
||||||
|
$file_manipulation = new FileManipulation($startPos, $endPos, "(" . $display_expr . " === '' || " . $display_expr . " === '0')");
|
||||||
|
$event->setFileReplacements([$file_manipulation]);
|
||||||
|
} elseif ($atomic_type instanceof Atomic\TArray) {
|
||||||
|
$file_manipulation = new FileManipulation($startPos, $endPos, $display_expr . " === []");
|
||||||
|
$event->setFileReplacements([$file_manipulation]);
|
||||||
|
} elseif ($atomic_type instanceof Atomic\TBool) {
|
||||||
|
$file_manipulation = new FileManipulation($startPos, $endPos, $display_expr . " === false");
|
||||||
|
$event->setFileReplacements([$file_manipulation]);
|
||||||
|
} else {
|
||||||
|
var_dump(get_class($atomic_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
17
src/Plugin.php
Normal file
17
src/Plugin.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
namespace Orklah\NotEmpty;
|
||||||
|
|
||||||
|
use Orklah\NotEmpty\Hooks\NotEmptyHooks;
|
||||||
|
use SimpleXMLElement;
|
||||||
|
use Psalm\Plugin\PluginEntryPointInterface;
|
||||||
|
use Psalm\Plugin\RegistrationInterface;
|
||||||
|
|
||||||
|
class Plugin implements PluginEntryPointInterface
|
||||||
|
{
|
||||||
|
public function __invoke(RegistrationInterface $registration, ?SimpleXMLElement $config = null): void
|
||||||
|
{
|
||||||
|
if(class_exists(NotEmptyHooks::class)){
|
||||||
|
$registration->registerHooksFromClass(NotEmptyHooks::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user