Skip to content

Commit

Permalink
Skip error in mock to avoid false positive in mixed (#1)
Browse files Browse the repository at this point in the history
* misc

* add test fixture

* rename to ReturnNullOverFalseRule
  • Loading branch information
TomasVotruba authored Jun 2, 2024
1 parent ada67c8 commit 53fad21
Show file tree
Hide file tree
Showing 12 changed files with 66 additions and 18 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"rector/rector": "^1.1",
"symplify/easy-coding-standard": "^12.1",
"phpstan/extension-installer": "^1.3",
"tomasvotruba/class-leak": "^0.2"
"tomasvotruba/class-leak": "^0.2",
"tracy/tracy": "^2.10"
},
"autoload": {
"psr-4": {
Expand Down
2 changes: 1 addition & 1 deletion config/extension.neon
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ rules:
- Rector\TypePerfect\Rules\NarrowPublicClassMethodParamTypeRule
- Rector\TypePerfect\Rules\NarrowPrivateClassMethodParamTypeRule
- Rector\TypePerfect\Rules\NarrowReturnObjectTypeRule
- Rector\TypePerfect\Rules\NoReturnFalseInNonBoolClassMethodRule
- Rector\TypePerfect\Rules\ReturnNullOverFalseRule

# no mixed
- Rector\TypePerfect\Rules\NoMixedPropertyFetcherRule
Expand Down
4 changes: 2 additions & 2 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ parameters:
- '#Method (.*?)::getCollectors\(\) return type with generic interface PHPStan\\Collectors\\Collector does not specify its types\: TNodeType, TValue#'

# overly detailed generics
- '#Class Rector\\TypePerfect\\Tests\\Rules\\(.*?) extends generic class PHPStan\\Testing\\RuleTestCase but does not specify its types\: TRule#'
- '#Method Rector\\TypePerfect\\Tests\\Rules\\(.*?)\:\:getRule\(\) return type with generic interface PHPStan\\Rules\\Rule does not specify its types\: TNodeType#'
- '#Rector\\TypePerfect\\Tests\\Rules\\(.*?) generic (class|interface)#'
- '#Method Rector\\TypePerfect\\Tests\\Rules\\(.*?)testRule\(\) has parameter \$expectedErrorsWithLines with no value type specified in iterable type array#'
21 changes: 21 additions & 0 deletions src/Rules/NoMixedMethodCallerRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public function processNode(Node $node, Scope $scope): array
}

$callerType = $scope->getType($node->var);

if (! $callerType instanceof MixedType) {
return [];
}
Expand All @@ -57,10 +58,30 @@ public function processNode(Node $node, Scope $scope): array
return [];
}

// if error, skip as well for false positive
if ($this->isPreviousTypeErrorType($node, $scope)) {
return [];
}

$printedMethodCall = $this->printerStandard->prettyPrintExpr($node->var);

return [
sprintf(self::ERROR_MESSAGE, $printedMethodCall),
];
}

private function isPreviousTypeErrorType(MethodCall $methodCall, Scope $scope): bool
{
$currentMethodCall = $methodCall;
while ($currentMethodCall->var instanceof MethodCall) {
$previousType = $scope->getType($currentMethodCall->var);
if ($previousType instanceof ErrorType) {
return true;
}

$currentMethodCall = $currentMethodCall->var;
}

return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
/**
* @implements Rule<ClassMethod>
*/
final readonly class NoReturnFalseInNonBoolClassMethodRule implements Rule
final readonly class ReturnNullOverFalseRule implements Rule
{
/**
* @api
Expand Down
21 changes: 21 additions & 0 deletions tests/Rules/NoMixedMethodCallerRule/Fixture/SkipPHPUnitMock.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Rector\TypePerfect\Tests\Rules\NoMixedMethodCallerRule\Fixture;

use PHPUnit\Framework\TestCase;
use Rector\TypePerfect\Tests\Rules\NoMixedMethodCallerRule\Source\SomeFinalClass;

final class SkipPHPUnitMock extends TestCase
{
public function test()
{
$someClassMock = $this->createMock(SomeFinalClass::class);

$someClassMock->expects($this->once())
->method('some')
->with($this->any())
->willReturn(1000);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@

final class NoMixedMethodCallerRuleTest extends RuleTestCase
{
/**
* @param mixed[]|array<int, array<int|string>> $expectedErrorsWithLines
*/
#[DataProvider('provideData')]
public function testRule(string $filePath, array $expectedErrorsWithLines): void
{
Expand All @@ -25,6 +22,7 @@ public static function provideData(): Iterator
{
yield [__DIR__ . '/Fixture/SkipKnownCallerType.php', []];
yield [__DIR__ . '/Fixture/SkipMockObject.php', []];
yield [__DIR__ . '/Fixture/SkipPHPUnitMock.php', []];

$errorMessage = sprintf(NoMixedMethodCallerRule::ERROR_MESSAGE, '$someType');
yield [__DIR__ . '/Fixture/MagicMethodName.php', [[$errorMessage, 11]]];
Expand Down
10 changes: 10 additions & 0 deletions tests/Rules/NoMixedMethodCallerRule/Source/SomeFinalClass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Rector\TypePerfect\Tests\Rules\NoMixedMethodCallerRule\Source;

final class SomeFinalClass
{
public function some()
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@

final class NoMixedPropertyFetcherRuleTest extends RuleTestCase
{
/**
* @param mixed[]|array<int, array<int|string>> $expectedErrorsWithLines
*/
#[DataProvider('provideData')]
public function testRule(string $filePath, array $expectedErrorsWithLines): void
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace Rector\TypePerfect\Tests\Rules\NoReturnFalseInNonBoolClassMethodRule\Fixture;
namespace Rector\TypePerfect\Tests\Rules\ReturnNullOverFalseRule\Fixture;

final class ReturnFalseOnly
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace Rector\TypePerfect\Tests\Rules\NoReturnFalseInNonBoolClassMethodRule\Fixture;
namespace Rector\TypePerfect\Tests\Rules\ReturnNullOverFalseRule\Fixture;

final class SkipReturnBool
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

declare(strict_types=1);

namespace Rector\TypePerfect\Tests\Rules\NoReturnFalseInNonBoolClassMethodRule;
namespace Rector\TypePerfect\Tests\Rules\ReturnNullOverFalseRule;

use Iterator;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;
use PHPUnit\Framework\Attributes\DataProvider;
use Rector\TypePerfect\Rules\NoReturnFalseInNonBoolClassMethodRule;
use Rector\TypePerfect\Rules\ReturnNullOverFalseRule;

final class NoReturnFalseInNonBoolClassMethodRuleTest extends RuleTestCase
final class ReturnNullOverFalseRuleTest extends RuleTestCase
{
/**
* @param mixed[] $expectedErrorMessagesWithLines
Expand All @@ -25,7 +25,7 @@ public static function provideData(): Iterator
{
yield [
__DIR__ . '/Fixture/ReturnFalseOnly.php',
[[NoReturnFalseInNonBoolClassMethodRule::ERROR_MESSAGE, 9]],
[[ReturnNullOverFalseRule::ERROR_MESSAGE, 9]],
];

yield [__DIR__ . '/Fixture/SkipReturnBool.php', []];
Expand All @@ -41,6 +41,6 @@ public static function getAdditionalConfigFiles(): array

protected function getRule(): Rule
{
return self::getContainer()->getByType(NoReturnFalseInNonBoolClassMethodRule::class);
return self::getContainer()->getByType(ReturnNullOverFalseRule::class);
}
}

0 comments on commit 53fad21

Please sign in to comment.