Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skip error in mock to avoid false positive in mixed #1

Merged
merged 3 commits into from
Jun 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
}
Loading