Skip to content
This repository has been archived by the owner on Sep 24, 2020. It is now read-only.

[Analyzer] Return and Yield in one Method #237

Closed
Closed
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
2 changes: 2 additions & 0 deletions .phpsa.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,6 @@ phpsa:
enabled: true
yoda_condition:
enabled: true
return_and_yield_in_one_method:
enabled: true

6 changes: 5 additions & 1 deletion docs/05_Analyzers.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Checks for casts that try to cast a type to itself.

#### CompareWithArray

Checks for `{type array} > 1` and similar and suggests use of `count()`.
Checks for `{type array} > 1` and similar and suggests use of `count()`.

#### ConstantNaming

Expand Down Expand Up @@ -130,6 +130,10 @@ Checks for use of old rand, srand, getrandmax functions and suggests alternative

Checks that regular expressions are syntactically correct.

#### ReturnAndYieldInOneMethod

Checks for using return and yield statements in a one method and discourages it.

#### StaticUsage

Discourages the use of static variables (not properties).
Expand Down
1 change: 1 addition & 0 deletions src/Analyzer/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ private static function getStatementPasses()
AnalyzerPass\Statement\StaticUsage::class,
AnalyzerPass\Statement\OptionalParamBeforeRequired::class,
AnalyzerPass\Statement\YodaCondition::class,
AnalyzerPass\Statement\ReturnAndYieldInOneMethod::class,
];
}

Expand Down
18 changes: 15 additions & 3 deletions src/Analyzer/Helper/ResolveExpressionTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,30 @@ public function resolveFunctionName(FuncCall $funcCall, Context $context)
}

/**
* Finds statements of the given class name.
*
* @param \PhpParser\Node[] $nodes
* @return \PhpParser\Node\Stmt\Return_
* @param string $stmtClass
* @return \PhpParser\Node\Stmt
*/
protected function findReturnStatement(array $nodes)
protected function findStatement(array $nodes, $stmtClass)
{
foreach ($this->traverseArray($nodes) as $node) {
if ($node instanceof Return_) {
if ($node instanceof $stmtClass) {
yield $node;
}
}
}

/**
* @param \PhpParser\Node[] $nodes
* @return \PhpParser\Node\Stmt\Return_
*/
protected function findReturnStatement(array $nodes)
{
return $this->findStatement($nodes, Return_::class);
}

/**
* For the code above
* Я атеист, но когда я начинал это писать, только Бог и я понимали, что я делаю
Expand Down
61 changes: 61 additions & 0 deletions src/Analyzer/Pass/Statement/ReturnAndYieldInOneMethod.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace PHPSA\Analyzer\Pass\Statement;

use PhpParser\Node\Expr\Yield_;
use PhpParser\Node\Stmt;
use PHPSA\Analyzer\Helper\DefaultMetadataPassTrait;
use PHPSA\Analyzer\Helper\ResolveExpressionTrait;
use PHPSA\Analyzer\Pass;
use PHPSA\Context;

class ReturnAndYieldInOneMethod implements Pass\AnalyzerPassInterface
{
use DefaultMetadataPassTrait,
ResolveExpressionTrait;

/**
* @param Stmt $stmt
* @param Context $context
* @return bool
*/
public function pass(Stmt $stmt, Context $context)
{
if ($this->returnStatementExists($stmt) && $this->yieldStatementExists($stmt)) {
$context->notice('return_and_yield_in_one_method', 'Do not use return and yield in a one method', $stmt);
return true;
}

return false;
}

/**
* @param Stmt $node
*
* @return bool
*/
private function returnStatementExists(Stmt $node)
{
return (bool)$this->findReturnStatement([$node])->current();
}

/**
* @param Stmt $node
*
* @return bool
*/
private function yieldStatementExists(Stmt $node)
{
return (bool)$this->findStatement([$node], Yield_::class)->current();
}

/**
* @return array
*/
public function getRegister()
{
return [
Stmt\ClassMethod::class,
];
}
}
44 changes: 44 additions & 0 deletions tests/analyze-fixtures/Statement/ReturnAndYieldInOneMethod.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

namespace Tests\Analyze\Fixtures\Statement;

class ReturnAndYieldInOneMethod
{
public function testReturnAndYield($a = true)
{
if ($a) {
return $a;
}
yield $a;
}

public function testReturnOnly($a = true)
{
if ($a) {
return $a;
}
return !$a;
}

public function testYieldOnly($a = true)
{
if ($a) {
yield $a;
}
}

public function testVoid(&$a)
{
$a = false;
}
}
?>
----------------------------
[
{
"type": "return_and_yield_in_one_method",
"message": "Do not use return and yield in a one method",
"file": "ReturnAndYieldInOneMethod.php",
"line": 6
}
]