Skip to content

Instantly share code, notes, and snippets.

@orklah
Created March 14, 2021 22:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save orklah/623142ef508160dc5f71c330ecacfeba to your computer and use it in GitHub Desktop.
Save orklah/623142ef508160dc5f71c330ecacfeba to your computer and use it in GitHub Desktop.
Psalm plugin to detect dynamic calls to static methods
<?php
use Psalm\CodeLocation;
use Psalm\Issue\CodeIssue;
use Psalm\Issue\PluginIssue;
use Psalm\IssueBuffer;
use Psalm\Plugin\EventHandler\AfterMethodCallAnalysisInterface;
use Psalm\Plugin\EventHandler\Event\AfterMethodCallAnalysisEvent;
use Psalm\Plugin\PluginEntryPointInterface;
use Psalm\Plugin\RegistrationInterface;
use Psalm\Type\Atomic\TNamedObject;
use Psalm\Type\Union;
class StaticOperator implements PluginEntryPointInterface, AfterMethodCallAnalysisInterface
{
public function __invoke(RegistrationInterface $psalm, ?SimpleXMLElement $config = null): void
{
}
public static function afterMethodCallAnalysis(AfterMethodCallAnalysisEvent $event): void
{
$expr = $event->getExpr();
if (!$expr instanceof \PhpParser\Node\Expr\MethodCall) {
return;
}
$nodeTypeProvider = $event->getStatementsSource()->getNodeTypeProvider();
$var_type = $nodeTypeProvider->getType($expr->var);
if ($var_type === null) {
return;
}
$class_name_atomic_types = $var_type->getAtomicTypes();
$class_name_atomic_type = array_shift($class_name_atomic_types);
if (!$class_name_atomic_type instanceof TNamedObject) {
return;
}
$class_name = $class_name_atomic_type->value;
$codebase = $event->getCodebase();
$class_storage = $codebase->classlike_storage_provider->get($class_name);
if (!isset($class_storage->methods[(string)$expr->name])) {
return;
}
$method_storage = $class_storage->methods[(string)$expr->name];
if (!$method_storage->is_static) {
return;
}
IssueBuffer::accepts(
new WrongOperatorForStaticMethod(
':: should be used as operator for static call',
new CodeLocation($event->getStatementsSource(), $expr)
),
$event->getStatementsSource()->getSuppressedIssues()
);
}
}
class WrongOperatorForStaticMethod extends PluginIssue
{
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment