1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-11 16:59:45 +01:00
psalm/examples/plugins/FunctionCasingChecker.php

105 lines
3.5 KiB
PHP
Raw Normal View History

2019-01-07 15:34:16 +01:00
<?php
2022-12-17 05:00:34 +01:00
2019-01-07 15:34:16 +01:00
namespace Psalm\Example\Plugin;
use Exception;
2019-01-07 15:34:16 +01:00
use PhpParser;
use Psalm\CodeLocation;
2022-12-18 17:15:15 +01:00
use Psalm\Internal\Analyzer\StatementsAnalyzer;
use Psalm\Internal\MethodIdentifier;
use Psalm\Issue\PluginIssue;
use Psalm\IssueBuffer;
use Psalm\Plugin\EventHandler\AfterFunctionCallAnalysisInterface;
use Psalm\Plugin\EventHandler\AfterMethodCallAnalysisInterface;
use Psalm\Plugin\EventHandler\Event\AfterFunctionCallAnalysisEvent;
use Psalm\Plugin\EventHandler\Event\AfterMethodCallAnalysisEvent;
2022-12-18 17:15:15 +01:00
use function end;
use function explode;
use function strtolower;
2019-01-07 15:34:16 +01:00
/**
* Checks that functions and methods are correctly-cased
2019-01-07 15:34:16 +01:00
*/
class FunctionCasingChecker implements AfterFunctionCallAnalysisInterface, AfterMethodCallAnalysisInterface
{
public static function afterMethodCallAnalysis(AfterMethodCallAnalysisEvent $event): void
{
$expr = $event->getExpr();
$codebase = $event->getCodebase();
$declaring_method_id = $event->getDeclaringMethodId();
$statements_source = $event->getStatementsSource();
2019-01-07 15:34:16 +01:00
if (!$expr->name instanceof PhpParser\Node\Identifier) {
return;
}
try {
2020-10-15 00:51:15 +02:00
/** @psalm-suppress ArgumentTypeCoercion */
2021-12-14 01:54:11 +01:00
$method_id = new MethodIdentifier(...explode('::', $declaring_method_id));
$function_storage = $codebase->methods->getStorage($method_id);
2019-01-07 15:34:16 +01:00
if ($function_storage->cased_name === '__call') {
return;
}
if ($function_storage->cased_name === '__callStatic') {
return;
}
2019-01-07 15:34:16 +01:00
if ($function_storage->cased_name !== (string)$expr->name) {
2022-12-17 05:00:34 +01:00
IssueBuffer::maybeAdd(
2019-01-07 15:34:16 +01:00
new IncorrectFunctionCasing(
'Function is incorrectly cased, expecting ' . $function_storage->cased_name,
2022-12-18 17:15:15 +01:00
new CodeLocation($statements_source, $expr->name),
2019-01-07 15:34:16 +01:00
),
2022-12-18 17:15:15 +01:00
$statements_source->getSuppressedIssues(),
2022-12-17 05:00:34 +01:00
);
2019-01-07 15:34:16 +01:00
}
} catch (Exception $e) {
2019-01-07 15:34:16 +01:00
// can throw if storage is missing
}
}
public static function afterFunctionCallAnalysis(AfterFunctionCallAnalysisEvent $event): void
{
$expr = $event->getExpr();
$codebase = $event->getCodebase();
$statements_source = $event->getStatementsSource();
$function_id = $event->getFunctionId();
2019-03-16 17:34:48 +01:00
if ($expr->name instanceof PhpParser\Node\Expr) {
2019-01-07 15:34:16 +01:00
return;
}
try {
$function_storage = $codebase->functions->getStorage(
$statements_source instanceof StatementsAnalyzer
2019-01-07 15:34:16 +01:00
? $statements_source
: null,
2022-12-18 17:15:15 +01:00
strtolower($function_id),
2019-01-07 15:34:16 +01:00
);
2019-11-25 21:20:31 +01:00
if (!$function_storage->cased_name) {
return;
}
2019-03-16 17:34:48 +01:00
$function_name_parts = explode('\\', $function_storage->cased_name);
if (end($function_name_parts) !== end($expr->name->parts)) {
2022-12-17 05:00:34 +01:00
IssueBuffer::maybeAdd(
2019-01-07 15:34:16 +01:00
new IncorrectFunctionCasing(
'Function is incorrectly cased, expecting ' . $function_storage->cased_name,
2022-12-18 17:15:15 +01:00
new CodeLocation($statements_source, $expr->name),
2019-01-07 15:34:16 +01:00
),
2022-12-18 17:15:15 +01:00
$statements_source->getSuppressedIssues(),
2022-12-17 05:00:34 +01:00
);
2019-01-07 15:34:16 +01:00
}
} catch (Exception $e) {
2019-01-07 15:34:16 +01:00
// can throw if storage is missing
}
}
}
class IncorrectFunctionCasing extends PluginIssue
{
2019-01-07 15:34:16 +01:00
}