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, #185 #263

Merged
merged 6 commits into from
Oct 31, 2016
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
4 changes: 4 additions & 0 deletions .phpsa.yml
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ phpsa:
property_definition_default_value:
enabled: true

# Checks for using return and yield statements in a one method and discourages it.
return_and_yield_in_one_method:
enabled: true

# Using octal, hexadecimal or binary integers is discouraged.
check_l_number_kind:
enabled: true
Expand Down
4 changes: 4 additions & 0 deletions docs/05_Analyzers.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,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 @@ -110,6 +110,7 @@ private static function getStatementPasses()
AnalyzerPass\Statement\YodaCondition::class,
AnalyzerPass\Statement\ForCondition::class,
AnalyzerPass\Statement\PropertyDefinitionDefaultValue::class,
AnalyzerPass\Statement\ReturnAndYieldInOneMethod::class,
];
}

Expand Down
12 changes: 5 additions & 7 deletions src/Analyzer/Helper/ResolveExpressionTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,23 @@ public function resolveFunctionName(FuncCall $funcCall, Context $context)
}

/**
* Return \Generator with Return_ statement(s)
* Return \Generator with Yield_ expression(s)
*
* @param \PhpParser\Node[] $nodes
* @return \Generator
*/
protected function findReturnStatement(array $nodes)
protected function findYieldExpression(array $nodes)
{
return $this->findNode($nodes, Return_::class);
return $this->findNode($nodes, Yield_::class);
}

/**
* Return \Generator with Yield_ expression(s)
*
* @param \PhpParser\Node[] $nodes
* @return \Generator
*/
protected function findYieldExpression(array $nodes)
protected function findReturnStatement(array $nodes)
{
return $this->findNode($nodes, Yield_::class);
return $this->findNode($nodes, Return_::class);
}

/**
Expand Down
49 changes: 49 additions & 0 deletions src/Analyzer/Pass/Statement/ReturnAndYieldInOneMethod.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace PHPSA\Analyzer\Pass\Statement;

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

class ReturnAndYieldInOneMethod implements Pass\AnalyzerPassInterface
{
const DESCRIPTION = 'Checks for using return and yield statements in a one method and discourages it.';

use DefaultMetadataPassTrait;
use ResolveExpressionTrait;

/**
* @param Stmt $stmt
* @param Context $context
* @return bool
*/
public function pass(Stmt $stmt, Context $context)
{
$yieldExists = \PHPSA\generatorHasValue($this->findYieldExpression([$stmt]));
if (!$yieldExists) {
// YieldFrom is another expression
$yieldExists = \PHPSA\generatorHasValue($this->findNode([$stmt], Expr\YieldFrom::class));
}

if ($yieldExists && \PHPSA\generatorHasValue($this->findReturnStatement([$stmt]))) {
$context->notice('return_and_yield_in_one_method', 'Do not use return and yield in a one method', $stmt);
return true;
}

return false;
}

/**
* @return array
*/
public function getRegister()
{
return [
Stmt\ClassMethod::class,
];
}
}
15 changes: 15 additions & 0 deletions src/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,18 @@ function nodeVisitorFactory($stmt, Context $context)

return $context->getExpressionCompiler()->compile($stmt);
}

/**
* Especial to protect HHVM: exception: Need to call next() first
*
* @param \Generator $generator
* @return bool
*/
function generatorHasValue(\Generator $generator)
{
foreach ($generator as $v) {
return true;
}

return false;
}
63 changes: 63 additions & 0 deletions tests/analyze-fixtures/Statement/ReturnAndYieldInOneMethod.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

namespace Tests\Analyze\Fixtures\Statement;

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

yield $a;
}

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

yield from [1, 2, 3, 4, 5];
}

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;
}
}
?>
----------------------------
PHPSA\Analyzer\Pass\Statement\ReturnAndYieldInOneMethod
----------------------------
[
{
"type": "return_and_yield_in_one_method",
"message": "Do not use return and yield in a one method",
"file": "ReturnAndYieldInOneMethod.php",
"line": 6
},
{
"type": "return_and_yield_in_one_method",
"message": "Do not use return and yield in a one method",
"file": "ReturnAndYieldInOneMethod.php",
"line": 15
}
]