diff --git a/extension.neon b/extension.neon index 41801463..e0847d57 100644 --- a/extension.neon +++ b/extension.neon @@ -165,6 +165,7 @@ services: - addNodeVisitor(200, Efabrica\PHPStanLatte\Compiler\NodeVisitor\TransformForeachWithIteratorNodeVisitor()) - addNodeVisitor(200, Efabrica\PHPStanLatte\Compiler\NodeVisitor\LinkNodeVisitor()) - addNodeVisitor(200, Efabrica\PHPStanLatte\Compiler\NodeVisitor\ChangeNotNullToEqualsNullNodeVisitor()) + - addNodeVisitor(200, Efabrica\PHPStanLatte\Compiler\NodeVisitor\ChangeGetParentNameToCompareWithNullNodeVisitor()) - addNodeVisitor(300, Efabrica\PHPStanLatte\Compiler\NodeVisitor\AddFormClassesNodeVisitor()) - addNodeVisitor(300, Efabrica\PHPStanLatte\Compiler\NodeVisitor\ReportNonExistingFieldOptionNodeVisitor()) - addNodeVisitor(9900, Efabrica\PHPStanLatte\Compiler\NodeVisitor\CleanupNodeVisitor()) diff --git a/src/Compiler/NodeVisitor/ChangeGetParentNameToCompareWithNullNodeVisitor.php b/src/Compiler/NodeVisitor/ChangeGetParentNameToCompareWithNullNodeVisitor.php new file mode 100644 index 00000000..f8839540 --- /dev/null +++ b/src/Compiler/NodeVisitor/ChangeGetParentNameToCompareWithNullNodeVisitor.php @@ -0,0 +1,66 @@ + + * if ($this->getParentName()) { + * return \get_defined_vars(); + * } + * + * + * to: + * + * if ($this->getParentName() !== null) { + * return \get_defined_vars(); + * } + * + */ +final class ChangeGetParentNameToCompareWithNullNodeVisitor extends NodeVisitorAbstract +{ + private NameResolver $nameResolver; + + public function __construct(NameResolver $nameResolver) + { + $this->nameResolver = $nameResolver; + } + + public function enterNode(Node $node): ?Node + { + if (!$node instanceof If_) { + return null; + } + + if (!$node->cond instanceof MethodCall) { + return null; + } + + if (!$node->cond->var instanceof Variable) { + return null; + } + + if ($node->cond->var->name !== 'this') { + return null; + } + + if ($this->nameResolver->resolve($node->cond->name) !== 'getParentName') { + return null; + } + + $node->cond = new NotIdentical($node->cond, new ConstFetch(new Name('null'))); + return $node; + } +} diff --git a/tests/Rule/LatteTemplatesRule/PresenterWithoutModule/LatteTemplatesRuleForPresenterTest.php b/tests/Rule/LatteTemplatesRule/PresenterWithoutModule/LatteTemplatesRuleForPresenterTest.php index fae81e67..c70e1d84 100644 --- a/tests/Rule/LatteTemplatesRule/PresenterWithoutModule/LatteTemplatesRuleForPresenterTest.php +++ b/tests/Rule/LatteTemplatesRule/PresenterWithoutModule/LatteTemplatesRuleForPresenterTest.php @@ -186,6 +186,11 @@ public function testVariables(): void 98, 'default.latte', ], + [ + 'Only booleans are allowed in an if condition, string|null given.', // Should be removed after issue https://github.com/efabrica-team/phpstan-latte/issues/444 is resolved + 100, + 'default.latte', + ], [ 'Undefined variable: $fromRenderDefault', 8, @@ -226,6 +231,11 @@ public function testVariables(): void 4, 'parent.latte', ], + [ + 'Only booleans are allowed in a ternary operator condition, int|false given.', // Should be removed after issue https://github.com/efabrica-team/phpstan-latte/issues/444 is resolved + 30, + 'specialConstructs.latte', + ], [ 'Undefined variable: $nonExistingVariable', 5, @@ -668,7 +678,7 @@ public function testComponents(): void public function testForms(): void { - $this->analyse([__DIR__ . '/Fixtures/FormsPresenter.php'], [ + $expectedErrors = [ [ 'Form control with name "password" probably does not exist.', 4, @@ -794,7 +804,36 @@ public function testForms(): void 10, '@layout.latte', ], - ]); + ]; + if (LatteVersion::isLatte3()) { + $expectedErrors[] = [ + 'PHPDoc tag @var with type Nette\Forms\Controls\BaseControl is not subtype of type Nette\Forms\Controls\TextArea.', // Should be removed after issue https://github.com/efabrica-team/phpstan-latte/issues/444 is resolved + 55, + 'default.latte', + ]; + } else { + $expectedErrors[] = [ + 'Only booleans are allowed in an if condition, Nette\Utils\Html|null given.', // Should be removed after issue https://github.com/efabrica-team/phpstan-latte/issues/444 is resolved + 10, + 'default.latte', + ]; + $expectedErrors[] = [ + 'Only booleans are allowed in an if condition, Nette\Utils\Html|null given.', // Should be removed after issue https://github.com/efabrica-team/phpstan-latte/issues/444 is resolved + 11, + 'default.latte', + ]; + $expectedErrors[] = [ + 'Only booleans are allowed in an if condition, Nette\Utils\Html|string|null given.', // Should be removed after issue https://github.com/efabrica-team/phpstan-latte/issues/444 is resolved + 12, + 'default.latte', + ]; + $expectedErrors[] = [ + 'Only booleans are allowed in an if condition, Nette\Utils\Html|string|null given.', // Should be removed after issue https://github.com/efabrica-team/phpstan-latte/issues/444 is resolved + 54, + 'default.latte', + ]; + } + $this->analyse([__DIR__ . '/Fixtures/FormsPresenter.php'], $expectedErrors); } public function testFilters(): void @@ -1100,6 +1139,11 @@ public function testLinks(): void 98, 'default.latte', ], + [ + 'Only booleans are allowed in a ternary operator condition, int|false given.', // Should be removed after issue https://github.com/efabrica-team/phpstan-latte/issues/444 is resolved + 102, + 'default.latte', + ], [ 'Undefined variable: $title', 7, diff --git a/tests/Rule/LatteTemplatesRule/PresenterWithoutModule/LatteTemplatesRuleForPresenterWithNoMappingTest.php b/tests/Rule/LatteTemplatesRule/PresenterWithoutModule/LatteTemplatesRuleForPresenterWithNoMappingTest.php index 243b4320..35ff7f3d 100644 --- a/tests/Rule/LatteTemplatesRule/PresenterWithoutModule/LatteTemplatesRuleForPresenterWithNoMappingTest.php +++ b/tests/Rule/LatteTemplatesRule/PresenterWithoutModule/LatteTemplatesRuleForPresenterWithNoMappingTest.php @@ -33,6 +33,11 @@ public function testLinks(): void 98, 'default.latte', ], + [ + 'Only booleans are allowed in a ternary operator condition, int|false given.', // Should be removed after issue https://github.com/efabrica-team/phpstan-latte/issues/444 is resolved + 102, + 'default.latte', + ], [ 'Parameter #1 $destination of method Nette\Application\UI\Component::link() expects string, Latte\Runtime\Html|string|false given.', 103, diff --git a/tests/Rule/LatteTemplatesRule/PresenterWithoutModule/phpstanCommand.neon b/tests/Rule/LatteTemplatesRule/PresenterWithoutModule/phpstanCommand.neon index d7449460..0f240c3d 100644 --- a/tests/Rule/LatteTemplatesRule/PresenterWithoutModule/phpstanCommand.neon +++ b/tests/Rule/LatteTemplatesRule/PresenterWithoutModule/phpstanCommand.neon @@ -1,4 +1,4 @@ parameters: latte: features: - phpstanCommand: "vendor/bin/phpstan analyse {dir} --level 8 --no-progress" + phpstanCommand: "vendor/bin/phpstan analyse {dir} --level 8 --no-progress -c tests/strict-rules.neon" diff --git a/tests/config.neon b/tests/config.neon index 848d719d..00488ef2 100644 --- a/tests/config.neon +++ b/tests/config.neon @@ -14,3 +14,4 @@ rules: includes: - %rootDir%/../../../vendor/phpstan/phpstan-nette/extension.neon - %rootDir%/../../../vendor/phpstan/phpstan-nette/rules.neon + - strict-rules.neon diff --git a/tests/strict-rules.neon b/tests/strict-rules.neon new file mode 100644 index 00000000..b92748a7 --- /dev/null +++ b/tests/strict-rules.neon @@ -0,0 +1,5 @@ +parameters: + reportMaybesInMethodSignatures: false + +includes: + - %rootDir%/../../../vendor/phpstan/phpstan-strict-rules/rules.neon