Skip to content
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
1 change: 1 addition & 0 deletions conf/bleedingEdge.neon
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ parameters:
assignToByRefForeachExpr: true
curlSetOptArrayTypes: true
checkDateIntervalConstructor: true
reportMethodPurityOverride: true
1 change: 1 addition & 0 deletions conf/config.neon
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ parameters:
assignToByRefForeachExpr: false
curlSetOptArrayTypes: false
checkDateIntervalConstructor: false
reportMethodPurityOverride: false
fileExtensions:
- php
checkAdvancedIsset: false
Expand Down
1 change: 1 addition & 0 deletions conf/parametersSchema.neon
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ parametersSchema:
assignToByRefForeachExpr: bool()
curlSetOptArrayTypes: bool()
checkDateIntervalConstructor: bool()
reportMethodPurityOverride: bool()
])
fileExtensions: listOf(string())
checkAdvancedIsset: bool()
Expand Down
1 change: 1 addition & 0 deletions conf/services.neon
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ services:
arguments:
reportMaybes: %reportMaybesInMethodSignatures%
reportStatic: %reportStaticMethodSignatures%
reportMethodPurityOverride: %featureToggles.reportMethodPurityOverride%

phpstanDiagnoseExtension:
class: PHPStan\Diagnose\PHPStanDiagnoseExtension
Expand Down
11 changes: 11 additions & 0 deletions src/Rules/Methods/MethodSignatureRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public function __construct(
private ParentMethodHelper $parentMethodHelper,
private bool $reportMaybes,
private bool $reportStatic,
private bool $reportMethodPurityOverride,
)
{
}
Expand All @@ -66,6 +67,16 @@ public function processNode(Node $node, Scope $scope): array
$errors = [];
$declaringClass = $method->getDeclaringClass();
foreach ($this->parentMethodHelper->collectParentMethods($methodName, $method->getDeclaringClass()) as [$parentMethod, $parentMethodDeclaringClass]) {
if ($this->reportMethodPurityOverride && $method->isPure()->no() && $parentMethod->isPure()->yes()) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Impure method %s::%s() overrides pure method %s::%s().',
$method->getDeclaringClass()->getDisplayName(),
$method->getName(),
$parentMethodDeclaringClass->getDisplayName(),
$parentMethod->getName(),
))->identifier('method.impure')->build();
}

$parentVariants = $parentMethod->getVariants();
if (count($parentVariants) !== 1) {
continue;
Expand Down
67 changes: 66 additions & 1 deletion tests/PHPStan/Rules/Methods/MethodSignatureRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class MethodSignatureRuleTest extends RuleTestCase

private bool $reportStatic;

private bool $reportMethodPurityOverride = false;

protected function getRule(): Rule
{
$phpVersion = new PhpVersion(PHP_VERSION_ID);
Expand All @@ -27,7 +29,7 @@ protected function getRule(): Rule

return new OverridingMethodRule(
$phpVersion,
new MethodSignatureRule(new ParentMethodHelper($phpClassReflectionExtension), $this->reportMaybes, $this->reportStatic),
new MethodSignatureRule(new ParentMethodHelper($phpClassReflectionExtension), $this->reportMaybes, $this->reportStatic, $this->reportMethodPurityOverride),
true,
new MethodParameterComparisonHelper($phpVersion),
new MethodVisibilityComparisonHelper(),
Expand Down Expand Up @@ -565,4 +567,67 @@ public function testBug14320(): void
$this->analyse([__DIR__ . '/data/bug-14320.php'], []);
}

public function testBug14563(): void
Comment thread
VincentLanglet marked this conversation as resolved.
{
$this->reportMaybes = true;
$this->reportStatic = true;
$this->reportMethodPurityOverride = true;
$this->analyse([__DIR__ . '/data/bug-14563.php'], [
[
'Impure method Bug14563\ChildImpureOverridesPure::pure() overrides pure method Bug14563\Foo::pure().',
31,
],
[
'Impure method Bug14563\ImpureImplementation::pureMethod() overrides pure method Bug14563\PureInterface::pureMethod().',
93,
],
[
'Impure method Bug14563\ImpureChildOfAllMethodsPure::method() overrides pure method Bug14563\AllMethodsPureParent::method().',
126,
],
[
'Impure method Bug14563\ChildImpureOverridesPureExtended::pure() overrides pure method Bug14563\Foo::pure().',
137,
],
[
'Impure method Bug14563\GrandchildImpureOverridesPure::pure() overrides pure method Bug14563\ChildPureOverridesPure::pure().',
148,
],
[
'Impure method Bug14563\ImpureMultipleInterfaces::sharedMethod() overrides pure method Bug14563\PureInterfaceA::sharedMethod().',
186,
],
[
'Impure method Bug14563\ImpureMultipleInterfaces::sharedMethod() overrides pure method Bug14563\PureInterfaceB::sharedMethod().',
186,
],
[
'Impure method Bug14563\ChildImpureOverridesPureVoid::pureVoid() overrides pure method Bug14563\VoidFoo::pureVoid().',
211,
],
[
'Impure method Bug14563\StaticChildImpureOverridesPure::pure() overrides pure method Bug14563\StaticFoo::pure().',
284,
],
[
'Impure method Bug14563\StaticImpureImplementation::pureMethod() overrides pure method Bug14563\StaticPureInterface::pureMethod().',
335,
],
]);
}

#[RequiresPhp('>= 8.0.0')]
public function testBug14563Trait(): void
{
$this->reportMaybes = true;
$this->reportStatic = true;
$this->reportMethodPurityOverride = true;
$this->analyse([__DIR__ . '/data/bug-14563-trait.php'], [
[
'Impure method Bug14563Trait\ImpureTraitUser::pureTraitMethod() overrides pure method Bug14563Trait\PureTrait::pureTraitMethod().',
19,
],
]);
}

}
2 changes: 1 addition & 1 deletion tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ protected function getRule(): Rule

return new OverridingMethodRule(
$phpVersion,
new MethodSignatureRule(new ParentMethodHelper($phpClassReflectionExtension), true, true),
new MethodSignatureRule(new ParentMethodHelper($phpClassReflectionExtension), true, true, false),
false,
new MethodParameterComparisonHelper($phpVersion),
new MethodVisibilityComparisonHelper(),
Expand Down
24 changes: 24 additions & 0 deletions tests/PHPStan/Rules/Methods/data/bug-14563-trait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php declare(strict_types = 1);

namespace Bug14563Trait;

trait PureTrait
{

/** @phpstan-pure */
abstract public function pureTraitMethod(): int;

}

class ImpureTraitUser
{

use PureTrait;

/** @phpstan-impure */
public function pureTraitMethod(): int
{
return random_int(0, 1);
}

}
Loading
Loading