Skip to content

Commit 58b0fd8

Browse files
authored
Add arrow function support (#179)
* Upgrade PHPCS requirement to 3.5 * Upgrade PHPCS requirement in README to 3.5 * Add basic tests for arrow functions * Make debug function variadic and work for objects * Add ScopeType constants * Remove unused variables in checkForSuperGlobal * Add tests for variable argument lists * Refactor scope detection to handle arrow functions * Add description to processVariable * Allow ellipses in argument lists * Only use T_FN if it exists * Don't assume token still exists when looking for closer * Remove null coalesce * Remove unused functions * Move isVariableANumericVariable to Helpers * Use isArrowFunction rather than T_FN in getContainingArrowFunctionIndex * Use isArrowFunction in getFunctionIndexForFunctionArgument for T_FN * Replace T_FN with isArrowFunction in getStartOfTokenScope * Replace T_FN in process * Stop using scope_condition for scope conditions in process * Stop using scope_condition in findVariableScopeExceptArrowFunctions * Replace scope_opener/closer with getArrowFunctionOpenClose
1 parent c3ab245 commit 58b0fd8

File tree

11 files changed

+759
-193
lines changed

11 files changed

+759
-193
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Plugin for PHP_CodeSniffer static analysis tool that adds analysis of problemati
1212

1313
### Requirements
1414

15-
VariableAnalysis requires PHP 5.6 or higher and [PHP CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) version 3.1.0 or higher.
15+
VariableAnalysis requires PHP 5.6 or higher and [PHP CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) version 3.5.0 or higher.
1616

1717
It also requires [PHPCSUtils](https://phpcsutils.com/) which must be installed as a PHPCS standard. If you are using composer, this will be done automatically (see below).
1818

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
namespace VariableAnalysis\Tests\VariableAnalysisSniff;
3+
4+
use VariableAnalysis\Tests\BaseTestCase;
5+
6+
class ArrowFunctionTest extends BaseTestCase {
7+
public function testArrowFunctions() {
8+
$fixtureFile = $this->getFixture('ArrowFunctionFixture.php');
9+
$phpcsFile = $this->prepareLocalFileForSniffs($fixtureFile);
10+
$phpcsFile->ruleset->setSniffProperty(
11+
'VariableAnalysis\Sniffs\CodeAnalysis\VariableAnalysisSniff',
12+
'allowUnusedParametersBeforeUsed',
13+
'true'
14+
);
15+
$phpcsFile->process();
16+
$lines = $this->getWarningLineNumbersFromFile($phpcsFile);
17+
$expectedWarnings = [
18+
9,
19+
14,
20+
19,
21+
24,
22+
30,
23+
34,
24+
51,
25+
57,
26+
61,
27+
67,
28+
71,
29+
];
30+
$this->assertEquals($expectedWarnings, $lines);
31+
}
32+
33+
public function testArrowFunctionsWithoutUnusedBeforeUsed() {
34+
$fixtureFile = $this->getFixture('ArrowFunctionFixture.php');
35+
$phpcsFile = $this->prepareLocalFileForSniffs($fixtureFile);
36+
$phpcsFile->ruleset->setSniffProperty(
37+
'VariableAnalysis\Sniffs\CodeAnalysis\VariableAnalysisSniff',
38+
'allowUnusedParametersBeforeUsed',
39+
'false'
40+
);
41+
$phpcsFile->process();
42+
$lines = $this->getWarningLineNumbersFromFile($phpcsFile);
43+
$expectedWarnings = [
44+
9,
45+
14,
46+
19,
47+
24,
48+
30,
49+
34,
50+
39,
51+
51,
52+
57,
53+
61,
54+
63,
55+
67,
56+
71,
57+
];
58+
$this->assertEquals($expectedWarnings, $lines);
59+
}
60+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
namespace VariableAnalysis\Tests\VariableAnalysisSniff;
3+
4+
use VariableAnalysis\Tests\BaseTestCase;
5+
6+
class VariableArgumentListTest extends BaseTestCase {
7+
public function testVariableArgumentList() {
8+
$fixtureFile = $this->getFixture('VariableArgumentListFixture.php');
9+
$phpcsFile = $this->prepareLocalFileForSniffs($fixtureFile);
10+
$phpcsFile->ruleset->setSniffProperty(
11+
'VariableAnalysis\Sniffs\CodeAnalysis\VariableAnalysisSniff',
12+
'allowUnusedParametersBeforeUsed',
13+
'true'
14+
);
15+
$phpcsFile->process();
16+
$lines = $this->getWarningLineNumbersFromFile($phpcsFile);
17+
$expectedWarnings = [
18+
6,
19+
15,
20+
23,
21+
33,
22+
38,
23+
];
24+
$this->assertEquals($expectedWarnings, $lines);
25+
}
26+
27+
public function testVariableArgumentListWithoutUnusedBeforeUsed() {
28+
$fixtureFile = $this->getFixture('VariableArgumentListFixture.php');
29+
$phpcsFile = $this->prepareLocalFileForSniffs($fixtureFile);
30+
$phpcsFile->ruleset->setSniffProperty(
31+
'VariableAnalysis\Sniffs\CodeAnalysis\VariableAnalysisSniff',
32+
'allowUnusedParametersBeforeUsed',
33+
'false'
34+
);
35+
$phpcsFile->process();
36+
$lines = $this->getWarningLineNumbersFromFile($phpcsFile);
37+
$expectedWarnings = [
38+
6,
39+
15,
40+
19,
41+
23,
42+
33,
43+
38,
44+
43,
45+
];
46+
$this->assertEquals($expectedWarnings, $lines);
47+
}
48+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
function arrowFunctionAsVariableWithNoWarnings($subject) {
4+
$arrowFunc = fn($foo) => $foo . $subject;
5+
echo $arrowFunc('hello');
6+
}
7+
8+
function arrowFunctionAsVariableWithUndefinedInside($subject) {
9+
$arrowFunc = fn($foo) => $foo . $bar . $subject; // undefined variable $bar
10+
echo $arrowFunc('hello');
11+
}
12+
13+
function arrowFunctionAsVariableWithUndefinedInClosure() {
14+
$arrowFunc = fn($foo) => $foo . $subject; // undefined variable $subject
15+
echo $arrowFunc('hello');
16+
}
17+
18+
function arrowFunctionAsVariableWithUnusedInside($subject) {
19+
$arrowFunc = fn($foo) => $subject; // unused variable $foo
20+
echo $arrowFunc('hello');
21+
}
22+
23+
function unusedArrowFunctionVariable($subject) {
24+
$arrowFunc = fn($foo) => $foo . $subject; // unused variable $arrowFunc
25+
}
26+
27+
function arrowFunctionAsVariableUsingOutsideArrow($subject) {
28+
$arrowFunc = fn($foo) => $foo . $subject;
29+
echo $arrowFunc('hello');
30+
echo $foo; // undefined variable $foo
31+
}
32+
33+
function arrowFunctionAsVariableWithUnusedInsideAfterUsed($subject) {
34+
$arrowFunc = fn($foo, $bar) => $foo . $subject; // unused variable $bar
35+
echo $arrowFunc('hello');
36+
}
37+
38+
function arrowFunctionAsVariableWithUsedInsideAfterUnused($subject) {
39+
$arrowFunc = fn($foo, $bar) => $bar . $subject; // unused variable $foo (but before used)
40+
echo $arrowFunc('hello');
41+
}
42+
43+
function arrowFunctionAsExpressionWithNoWarnings() {
44+
$posts = [];
45+
$ids = array_map(fn($post) => $post->id, $posts);
46+
echo $ids;
47+
}
48+
49+
function arrowFunctionAsExpressionWithUndefinedVariableInside() {
50+
$posts = [];
51+
$ids = array_map(fn($post) => $post->id . $foo, $posts); // undefined variable $foo
52+
echo $ids;
53+
}
54+
55+
function arrowFunctionAsExpressionWithUnusedVariableInside($subject) {
56+
$posts = [];
57+
$ids = array_map(fn($post) => $subject, $posts); // unused variable $post
58+
echo $ids;
59+
}
60+
61+
function arrowFunctionAsExpressionWithUsedAfterUnused($subject) { // unused variable $subject
62+
$posts = [];
63+
$ids = array_map(fn($foo, $post) => $post->id, $posts); // unused variable $foo (but before used)
64+
echo $ids;
65+
}
66+
67+
function arrowFunctionAsExpressionWithUnusedVariableOutsideArrow($subject) { //unused variable $subject
68+
$posts = [];
69+
$ids = array_map(fn($post) => $post->id, $posts);
70+
echo $ids;
71+
echo $post; // undefined variable $post;
72+
}
73+
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
function functionWithVariableArgumentsAlone(...$rest) {
3+
echo $rest[0];
4+
}
5+
6+
function functionWithVariableArgumentsAloneUnused(...$rest) { // unused variable $rest
7+
echo "Hello";
8+
}
9+
10+
function functionWithVariableArgumentsAfterOther($first, ...$rest) {
11+
echo $first;
12+
echo $rest[0];
13+
}
14+
15+
function functionWithVariableArgumentsUnusedAfterOther($first, ...$rest) { // unused variable $rest
16+
echo $first;
17+
}
18+
19+
function functionWithVariableArgumentsAfterOtherUnused($first, ...$rest) { // unused variable $first (but before used)
20+
echo $rest[0];
21+
}
22+
23+
function functionWithVariableArgumentsUnusedAfterOtherUnused($first, ...$rest) { // unused variable $rest and unused variable $first
24+
echo $first;
25+
}
26+
27+
function functionWithArrowVariableArgumentsAlone($subject) {
28+
$arrowFunc = fn(...$foo) => $foo[0] . $subject;
29+
echo $arrowFunc('hello');
30+
}
31+
32+
function functionWithArrowVariableArgumentsAloneUnused($subject) {
33+
$arrowFunc = fn(...$foo) => $subject; // unused variable $foo
34+
echo $arrowFunc('hello');
35+
}
36+
37+
function functionWithArrowVariableArgumentsUnusedAfterOther() {
38+
$arrowFunc = fn($first, ...$foo) => $first; // unused variable $foo
39+
echo $arrowFunc('hello');
40+
}
41+
42+
function functionWithArrowVariableArgumentsAfterOtherUnused() {
43+
$arrowFunc = fn($first, ...$foo) => $foo[0]; // unused variable $first (but before used)
44+
echo $arrowFunc('hello');
45+
}

0 commit comments

Comments
 (0)