Skip to content

Commit 893f5c8

Browse files
committed
feat: ignore static mixin/macro calls in facades
1 parent 4b9606e commit 893f5c8

File tree

7 files changed

+91
-0
lines changed

7 files changed

+91
-0
lines changed

extension.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,11 @@ services:
698698
class: Illuminate\Filesystem\Filesystem
699699
autowired: self
700700

701+
-
702+
class: Larastan\Larastan\Ignore\FacadeStaticCallIgnoreExtension
703+
tags:
704+
- phpstan.ignoreErrorExtension
705+
701706
rules:
702707
- Larastan\Larastan\Rules\UselessConstructs\NoUselessWithFunctionCallsRule
703708
- Larastan\Larastan\Rules\UselessConstructs\NoUselessValueFunctionCallsRule
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Larastan\Larastan\Ignore;
6+
7+
use Illuminate\Support\Facades\Facade;
8+
use PhpParser\Node;
9+
use PhpParser\Node\Expr\StaticCall;
10+
use PhpParser\Node\Identifier;
11+
use PhpParser\Node\Name;
12+
use PHPStan\Analyser\Error;
13+
use PHPStan\Analyser\IgnoreErrorExtension;
14+
use PHPStan\Analyser\Scope;
15+
use PHPStan\Type\ObjectType;
16+
17+
final class FacadeStaticCallIgnoreExtension implements IgnoreErrorExtension
18+
{
19+
public function shouldIgnore(Error $error, Node $node, Scope $scope): bool
20+
{
21+
if ($error->getIdentifier() !== 'method.staticCall') {
22+
return false;
23+
}
24+
25+
if (
26+
! $node instanceof StaticCall
27+
|| ! $node->name instanceof Identifier
28+
) {
29+
return false;
30+
}
31+
32+
$type = $node->class instanceof Name
33+
? $scope->resolveTypeByName($node->class)
34+
: $scope->getType($node->class);
35+
36+
if (! (new ObjectType(Facade::class))->isSuperTypeOf($type)->yes()) {
37+
return false;
38+
}
39+
40+
$method = $node->name->toString();
41+
42+
foreach ($type->getObjectClassReflections() as $classReflection) {
43+
if ($classReflection->hasNativeMethod($method)) {
44+
return false;
45+
}
46+
}
47+
48+
return true;
49+
}
50+
}

tests/Integration/IntegrationTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public static function dataIntegrationTests(): iterable
3131
yield [__DIR__ . '/data/model-factories.php'];
3232
yield [__DIR__ . '/data/blade-view.php'];
3333
yield [__DIR__ . '/data/helpers.php'];
34+
yield [__DIR__ . '/data/facade-static-call.php', [9 => ['Static call to instance method App\Facades\Importer::facadeMethod().']]];
3435

3536
yield [
3637
__DIR__ . '/data/model-property-builder.php',
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace FacadeStaticCall;
4+
5+
use App\Facades\Importer;
6+
7+
Importer::foo();
8+
Importer::getKey();
9+
Importer::facadeMethod();
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace App\Facades;
4+
5+
use App\Importer as Instance;
6+
use Illuminate\Support\Facades\Facade;
7+
use Illuminate\Support\Str;
8+
9+
class Importer extends Facade
10+
{
11+
protected static function getFacadeAccessor(): string
12+
{
13+
return Instance::class;
14+
}
15+
16+
public function facadeMethod(): string
17+
{
18+
return Str::random(5);
19+
}
20+
}

tests/application/app/Importer.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
namespace App;
66

77
use Illuminate\Support\Str;
8+
use Illuminate\Support\Traits\Macroable;
89

910
class Importer
1011
{
12+
use Macroable;
13+
1114
/** @var bool */
1215
public $isImported;
1316

tests/bootstrap.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
declare(strict_types=1);
44

5+
use App\Importer;
56
use Illuminate\Auth\RequestGuard;
67
use Illuminate\Auth\SessionGuard;
78
use Illuminate\Database\Eloquent\Builder;
@@ -36,6 +37,8 @@
3637

3738
Cache::macro('rememberIf', static fn ($cond, $key, $ttl, $callback): mixed => $cond ? Cache::remember($key, $ttl, $callback) : $callback());
3839

40+
Importer::macro('foo', fn () => $this);
41+
3942
class CustomCollectionMacro
4043
{
4144
public function registerMacro(): void

0 commit comments

Comments
 (0)