Skip to content

Commit

Permalink
Enhancement: Implement NoReturnByReferenceRule
Browse files Browse the repository at this point in the history
  • Loading branch information
localheinz committed Feb 17, 2025
1 parent 4e42c4f commit e08a5cf
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 0 deletions.
10 changes: 10 additions & 0 deletions rules.neon
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ conditionalTags:
phpstan.rules.rule: %ergebnis.noParameterWithNullableTypeDeclaration.enabled%
Ergebnis\PHPStan\Rules\Functions\NoParameterWithNullDefaultValueRule:
phpstan.rules.rule: %ergebnis.noParameterWithNullDefaultValue.enabled%
Ergebnis\PHPStan\Rules\Functions\NoReturnByReferenceRule:
phpstan.rules.rule: %ergebnis.noReturnByReference.enabled%
Ergebnis\PHPStan\Rules\Methods\FinalInAbstractClassRule:
phpstan.rules.rule: %ergebnis.finalInAbstractClass.enabled%
Ergebnis\PHPStan\Rules\Methods\NoConstructorParameterWithDefaultValueRule:
Expand Down Expand Up @@ -84,6 +86,8 @@ parameters:
enabled: true
noParameterWithNullDefaultValue:
enabled: true
noReturnByReference:
enabled: true
noSwitch:
enabled: true
privateInFinalClass:
Expand Down Expand Up @@ -140,6 +144,9 @@ parametersSchema:
noParameterWithNullDefaultValue: structure([
enabled: bool(),
])
noReturnByReference: structure([
enabled: bool(),
])
noSwitch: structure([
enabled: bool(),
])
Expand Down Expand Up @@ -205,6 +212,9 @@ services:
-
class: Ergebnis\PHPStan\Rules\Functions\NoParameterWithNullDefaultValueRule

-
class: Ergebnis\PHPStan\Rules\Functions\NoReturnByReferenceRule

-
class: Ergebnis\PHPStan\Rules\Methods\FinalInAbstractClassRule

Expand Down
5 changes: 5 additions & 0 deletions src/ErrorIdentifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ public static function noNullableReturnTypeDeclaration(): self
return new self('noNullableReturnTypeDeclaration');
}

public static function noReturnByReference(): self
{
return new self('noReturnByReference');
}

public static function noSwitch(): self
{
return new self('noSwitch');
Expand Down
54 changes: 54 additions & 0 deletions src/Functions/NoReturnByReferenceRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2018-2025 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/phpstan-rules
*/

namespace Ergebnis\PHPStan\Rules\Functions;

use Ergebnis\PHPStan\Rules\ErrorIdentifier;
use PhpParser\Node;
use PHPStan\Analyser;
use PHPStan\Rules;

/**
* @implements Rules\Rule<Node\Stmt\Function_>
*/
final class NoReturnByReferenceRule implements Rules\Rule
{
public function getNodeType(): string
{
return Node\Stmt\Function_::class;
}

public function processNode(
Node $node,
Analyser\Scope $scope
): array {
if (0 === \count($node->params)) {
return [];
}

if (false === $node->byRef) {
return [];
}

$message = \sprintf(
'Function %s() returns by reference.',
$node->namespacedName,
);

return [
Rules\RuleErrorBuilder::message($message)
->identifier(ErrorIdentifier::noReturnByReference()->toString())
->build(),
];
}
}
14 changes: 14 additions & 0 deletions test/Fixture/Functions/NoReturnByReferenceRule/script.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace Ergebnis\PHPStan\Rules\Test\Fixture\Functions\NoReturnByReferenceRule;

function foo(): void
{
}

function &bar($bar)
{
return $bar;
}
49 changes: 49 additions & 0 deletions test/Integration/Functions/NoReturnByReferenceRuleTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2018-2025 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/phpstan-rules
*/

namespace Ergebnis\PHPStan\Rules\Test\Integration\Functions;

use Ergebnis\PHPStan\Rules\Functions;
use Ergebnis\PHPStan\Rules\Test;
use PHPStan\Rules;
use PHPStan\Testing;

/**
* @covers \Ergebnis\PHPStan\Rules\Functions\NoReturnByReferenceRule
*
* @uses \Ergebnis\PHPStan\Rules\ErrorIdentifier
*
* @extends Testing\RuleTestCase<Functions\NoReturnByReferenceRule>
*/
final class NoReturnByReferenceRuleTest extends Testing\RuleTestCase
{
use Test\Util\Helper;

public function testNoReturnByReferenceRule(): void
{
$this->analyse(
self::phpFilesIn(__DIR__ . '/../../Fixture/Functions/NoReturnByReferenceRule'),
[
[
'Function Ergebnis\PHPStan\Rules\Test\Fixture\Functions\NoReturnByReferenceRule\baz() returns by reference.',
11,
],
],
);
}

protected function getRule(): Rules\Rule
{
return new Functions\NoReturnByReferenceRule();
}
}
7 changes: 7 additions & 0 deletions test/Unit/ErrorIdentifierTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,13 @@ public function testNoParameterWithNullableTypeDeclarationReturnsErrorIdentifier
self::assertSame('ergebnis.noParameterWithNullableTypeDeclaration', $errorIdentifier->toString());
}

public function testNoReturnByReferenceErrorIdentifier(): void
{
$errorIdentifier = ErrorIdentifier::noReturnByReference();

self::assertSame('ergebnis.noReturnByReference', $errorIdentifier->toString());
}

public function testNoSwitchReturnsErrorIdentifier(): void
{
$errorIdentifier = ErrorIdentifier::noSwitch();
Expand Down

0 comments on commit e08a5cf

Please sign in to comment.