diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..ef4017a --- /dev/null +++ b/.editorconfig @@ -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 diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..12527b1 --- /dev/null +++ b/composer.json @@ -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" + } +} diff --git a/src/Hooks/NotEmptyHooks.php b/src/Hooks/NotEmptyHooks.php new file mode 100644 index 0000000..e84aa6e --- /dev/null +++ b/src/Hooks/NotEmptyHooks.php @@ -0,0 +1,75 @@ +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; + } +} diff --git a/src/Plugin.php b/src/Plugin.php new file mode 100644 index 0000000..e608822 --- /dev/null +++ b/src/Plugin.php @@ -0,0 +1,17 @@ +registerHooksFromClass(NotEmptyHooks::class); + } + } +}