diff --git a/src/Reflection/Nette/HtmlClassReflectionExtension.php b/src/Reflection/Nette/HtmlClassReflectionExtension.php index 1f6d391..c71a789 100644 --- a/src/Reflection/Nette/HtmlClassReflectionExtension.php +++ b/src/Reflection/Nette/HtmlClassReflectionExtension.php @@ -7,13 +7,15 @@ use PHPStan\Reflection\MethodsClassReflectionExtension; use PHPStan\Reflection\PropertiesClassReflectionExtension; use PHPStan\Reflection\PropertyReflection; +use function in_array; class HtmlClassReflectionExtension implements MethodsClassReflectionExtension, PropertiesClassReflectionExtension { public function hasMethod(ClassReflection $classReflection, string $methodName): bool { - return $classReflection->is('Nette\Utils\Html'); + // The static factories declared in the stub, which would otherwise be taken for attribute setters + return $classReflection->is('Nette\Utils\Html') && !in_array($methodName, ['text', 'html'], true); } public function getMethod(ClassReflection $classReflection, string $methodName): MethodReflection diff --git a/stubs/Utils/Html.stub b/stubs/Utils/Html.stub index 1ee2b50..6018297 100644 --- a/stubs/Utils/Html.stub +++ b/stubs/Utils/Html.stub @@ -5,6 +5,8 @@ namespace Nette\Utils; /** * @implements \IteratorAggregate * @implements \ArrayAccess + * @method static static text(mixed $text) + * @method static static html(mixed $html) */ class Html implements \ArrayAccess, \IteratorAggregate { diff --git a/tests/Reflection/Nette/HtmlClassReflectionExtensionTest.php b/tests/Reflection/Nette/HtmlClassReflectionExtensionTest.php index 6dc1978..96f0af1 100644 --- a/tests/Reflection/Nette/HtmlClassReflectionExtensionTest.php +++ b/tests/Reflection/Nette/HtmlClassReflectionExtensionTest.php @@ -28,10 +28,22 @@ public function dataHasMethod(): array return [ [ Html::class, + 'href', true, ], + [ + Html::class, + 'text', + false, + ], + [ + Html::class, + 'html', + false, + ], [ stdClass::class, + 'href', false, ], ]; @@ -40,10 +52,10 @@ public function dataHasMethod(): array /** * @dataProvider dataHasMethod */ - public function testHasMethod(string $className, bool $result): void + public function testHasMethod(string $className, string $methodName, bool $result): void { $classReflection = $this->reflectionProvider->getClass($className); - self::assertSame($result, $this->extension->hasMethod($classReflection, 'href')); + self::assertSame($result, $this->extension->hasMethod($classReflection, $methodName)); } public function testGetMethod(): void diff --git a/tests/Rule/Nette/HtmlStaticFactoriesTest.php b/tests/Rule/Nette/HtmlStaticFactoriesTest.php new file mode 100644 index 0000000..311f1d9 --- /dev/null +++ b/tests/Rule/Nette/HtmlStaticFactoriesTest.php @@ -0,0 +1,32 @@ + + */ +class HtmlStaticFactoriesTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return self::getContainer()->getByType(CallStaticMethodsRule::class); // @phpstan-ignore phpstanApi.classConstant + } + + public function testRule(): void + { + $this->analyse([__DIR__ . '/data/html-static-factories.php'], []); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/../../../extension.neon', + ]; + } + +} diff --git a/tests/Rule/Nette/data/html-static-factories.php b/tests/Rule/Nette/data/html-static-factories.php new file mode 100644 index 0000000..e4d0863 --- /dev/null +++ b/tests/Rule/Nette/data/html-static-factories.php @@ -0,0 +1,12 @@ +html'); + return $text->addHtml($html); +}