Skip to content

Commit 3167110

Browse files
committed
Refactor/TokenIs: add new isUnaryPlusMinus() utility method
This adds a new utility method: * `isUnaryPlusMinus()` - to check whether a plus/minus sign is a unary or an arithmetic operator. Returns boolean. Includes dedicated unit tests.
1 parent da91694 commit 3167110

File tree

6 files changed

+533
-0
lines changed

6 files changed

+533
-0
lines changed

package.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ http://pear.php.net/dtd/package-2.0.xsd">
116116
<file baseinstalldir="" name="IsReferenceTest.php" role="test" />
117117
<file baseinstalldir="" name="IsShortListTest.inc" role="test" />
118118
<file baseinstalldir="" name="IsShortListTest.php" role="test" />
119+
<file baseinstalldir="" name="IsUnaryPlusMinusJSTest.js" role="test" />
120+
<file baseinstalldir="" name="IsUnaryPlusMinusJSTest.php" role="test" />
121+
<file baseinstalldir="" name="IsUnaryPlusMinusTest.inc" role="test" />
122+
<file baseinstalldir="" name="IsUnaryPlusMinusTest.php" role="test" />
119123
</dir>
120124
<dir name="UseStatements">
121125
<file baseinstalldir="" name="SplitImportUseStatementTest.inc" role="test" />
@@ -1937,6 +1941,10 @@ http://pear.php.net/dtd/package-2.0.xsd">
19371941
<install as="CodeSniffer/Core/Util/Sniffs/TokenIs/IsReferenceTest.inc" name="tests/Core/Util/Sniffs/TokenIs/IsReferenceTest.inc" />
19381942
<install as="CodeSniffer/Core/Util/Sniffs/TokenIs/IsShortListTest.php" name="tests/Core/Util/Sniffs/TokenIs/IsShortListTest.php" />
19391943
<install as="CodeSniffer/Core/Util/Sniffs/TokenIs/IsShortListTest.inc" name="tests/Core/Util/Sniffs/TokenIs/IsShortListTest.inc" />
1944+
<install as="CodeSniffer/Core/Util/Sniffs/TokenIs/IsUnaryPlusMinusJSTest.php" name="tests/Core/Util/Sniffs/TokenIs/IsUnaryPlusMinusJSTest.php" />
1945+
<install as="CodeSniffer/Core/Util/Sniffs/TokenIs/IsUnaryPlusMinusJSTest.js" name="tests/Core/Util/Sniffs/TokenIs/IsUnaryPlusMinusJSTest.js" />
1946+
<install as="CodeSniffer/Core/Util/Sniffs/TokenIs/IsUnaryPlusMinusTest.php" name="tests/Core/Util/Sniffs/TokenIs/IsUnaryPlusMinusTest.php" />
1947+
<install as="CodeSniffer/Core/Util/Sniffs/TokenIs/IsUnaryPlusMinusTest.inc" name="tests/Core/Util/Sniffs/TokenIs/IsUnaryPlusMinusTest.inc" />
19401948
<install as="CodeSniffer/Core/Util/Sniffs/UseStatements/SplitImportUseStatementTest.php" name="tests/Core/Util/Sniffs/UseStatements/SplitImportUseStatementTest.php" />
19411949
<install as="CodeSniffer/Core/Util/Sniffs/UseStatements/SplitImportUseStatementTest.inc" name="tests/Core/Util/Sniffs/UseStatements/SplitImportUseStatementTest.inc" />
19421950
<install as="CodeSniffer/Core/Util/Sniffs/UseStatements/UseTypeTest.php" name="tests/Core/Util/Sniffs/UseStatements/UseTypeTest.php" />
@@ -2007,6 +2015,10 @@ http://pear.php.net/dtd/package-2.0.xsd">
20072015
<install as="CodeSniffer/Core/Util/Sniffs/TokenIs/IsReferenceTest.inc" name="tests/Core/Util/Sniffs/TokenIs/IsReferenceTest.inc" />
20082016
<install as="CodeSniffer/Core/Util/Sniffs/TokenIs/IsShortListTest.php" name="tests/Core/Util/Sniffs/TokenIs/IsShortListTest.php" />
20092017
<install as="CodeSniffer/Core/Util/Sniffs/TokenIs/IsShortListTest.inc" name="tests/Core/Util/Sniffs/TokenIs/IsShortListTest.inc" />
2018+
<install as="CodeSniffer/Core/Util/Sniffs/TokenIs/IsUnaryPlusMinusJSTest.php" name="tests/Core/Util/Sniffs/TokenIs/IsUnaryPlusMinusJSTest.php" />
2019+
<install as="CodeSniffer/Core/Util/Sniffs/TokenIs/IsUnaryPlusMinusJSTest.js" name="tests/Core/Util/Sniffs/TokenIs/IsUnaryPlusMinusJSTest.js" />
2020+
<install as="CodeSniffer/Core/Util/Sniffs/TokenIs/IsUnaryPlusMinusTest.php" name="tests/Core/Util/Sniffs/TokenIs/IsUnaryPlusMinusTest.php" />
2021+
<install as="CodeSniffer/Core/Util/Sniffs/TokenIs/IsUnaryPlusMinusTest.inc" name="tests/Core/Util/Sniffs/TokenIs/IsUnaryPlusMinusTest.inc" />
20102022
<install as="CodeSniffer/Core/Util/Sniffs/UseStatements/SplitImportUseStatementTest.php" name="tests/Core/Util/Sniffs/UseStatements/SplitImportUseStatementTest.php" />
20112023
<install as="CodeSniffer/Core/Util/Sniffs/UseStatements/SplitImportUseStatementTest.inc" name="tests/Core/Util/Sniffs/UseStatements/SplitImportUseStatementTest.inc" />
20122024
<install as="CodeSniffer/Core/Util/Sniffs/UseStatements/UseTypeTest.php" name="tests/Core/Util/Sniffs/UseStatements/UseTypeTest.php" />

src/Util/Sniffs/TokenIs.php

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,4 +207,90 @@ public static function isShortList(File $phpcsFile, $stackPtr)
207207
}//end isShortList()
208208

209209

210+
/**
211+
* Determine whether a T_MINUS/T_PLUS token is a unary operator.
212+
*
213+
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
214+
* @param int $stackPtr The position of the plus/minus token.
215+
*
216+
* @return bool True if the token passed is a unary operator.
217+
* False otherwise or if the token is not a T_PLUS/T_MINUS token.
218+
*/
219+
public static function isUnaryPlusMinus(File $phpcsFile, $stackPtr)
220+
{
221+
$tokens = $phpcsFile->getTokens();
222+
223+
if (isset($tokens[$stackPtr]) === false
224+
|| ($tokens[$stackPtr]['code'] !== T_PLUS
225+
&& $tokens[$stackPtr]['code'] !== T_MINUS)
226+
) {
227+
return false;
228+
}
229+
230+
$next = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true);
231+
if ($next === false) {
232+
// Live coding or parse error.
233+
return false;
234+
}
235+
236+
if (isset(Tokens::$operators[$tokens[$next]['code']]) === true) {
237+
// Next token is an operator, so this is not a unary.
238+
return false;
239+
}
240+
241+
$prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true);
242+
243+
if ($tokens[$prev]['code'] === T_RETURN) {
244+
// Just returning a positive/negative value; eg. (return -1).
245+
return true;
246+
}
247+
248+
if (isset(Tokens::$operators[$tokens[$prev]['code']]) === true) {
249+
// Just trying to operate on a positive/negative value; eg. ($var * -1).
250+
return true;
251+
}
252+
253+
if (isset(Tokens::$comparisonTokens[$tokens[$prev]['code']]) === true) {
254+
// Just trying to compare a positive/negative value; eg. ($var === -1).
255+
return true;
256+
}
257+
258+
if (isset(Tokens::$booleanOperators[$tokens[$prev]['code']]) === true) {
259+
// Just trying to compare a positive/negative value; eg. ($var || -1 === $b).
260+
return true;
261+
}
262+
263+
if (isset(Tokens::$assignmentTokens[$tokens[$prev]['code']]) === true) {
264+
// Just trying to assign a positive/negative value; eg. ($var = -1).
265+
return true;
266+
}
267+
268+
if (isset(Tokens::$castTokens[$tokens[$prev]['code']]) === true) {
269+
// Just casting a positive/negative value; eg. (string) -$var.
270+
return true;
271+
}
272+
273+
// Other indicators that a plus/minus sign is a unary operator.
274+
$invalidTokens = [
275+
T_COMMA => true,
276+
T_OPEN_PARENTHESIS => true,
277+
T_OPEN_SQUARE_BRACKET => true,
278+
T_OPEN_SHORT_ARRAY => true,
279+
T_COLON => true,
280+
T_INLINE_THEN => true,
281+
T_INLINE_ELSE => true,
282+
T_CASE => true,
283+
T_OPEN_CURLY_BRACKET => true,
284+
];
285+
286+
if (isset($invalidTokens[$tokens[$prev]['code']]) === true) {
287+
// Just trying to use a positive/negative value; eg. myFunction($var, -2).
288+
return true;
289+
}
290+
291+
return false;
292+
293+
}//end isUnaryPlusMinus()
294+
295+
210296
}//end class
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/* testNonUnaryPlus */
2+
result = 1 + 2;
3+
4+
/* testNonUnaryMinus */
5+
result = 1-2;
6+
7+
/* testUnaryMinusColon */
8+
$.localScroll({offset: {top: -32}});
9+
10+
switch (result) {
11+
/* testUnaryMinusCase */
12+
case -1:
13+
break;
14+
}
15+
16+
/* testUnaryMinusInlineIf */
17+
result = x?-y:z;
18+
19+
/* testUnaryPlusInlineThen */
20+
result = x ? y : +z;
21+
22+
/* testUnaryMinusInlineLogical */
23+
if (true || -1 == b) {}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
/**
3+
* Tests for the \PHP_CodeSniffer\Util\Sniffs\TokenIs::isUnaryPlusMinus() method.
4+
*
5+
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
6+
* @copyright 2019 Juliette Reinders Folmer. All rights reserved.
7+
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
8+
*/
9+
10+
namespace PHP_CodeSniffer\Tests\Core\Util\Sniffs\TokenIs;
11+
12+
class IsUnaryPlusMinusJSTest extends IsUnaryPlusMinusTest
13+
{
14+
15+
/**
16+
* The file extension of the test case file (without leading dot).
17+
*
18+
* @var string
19+
*/
20+
protected static $fileExtension = 'js';
21+
22+
23+
/**
24+
* Data provider.
25+
*
26+
* @see IsUnaryPlusMinusTest::testIsUnaryPlusMinus()
27+
*
28+
* @return array
29+
*/
30+
public function dataIsUnaryPlusMinus()
31+
{
32+
return [
33+
[
34+
'/* testNonUnaryPlus */',
35+
false,
36+
],
37+
[
38+
'/* testNonUnaryMinus */',
39+
false,
40+
],
41+
[
42+
'/* testUnaryMinusColon */',
43+
true,
44+
],
45+
[
46+
'/* testUnaryMinusCase */',
47+
true,
48+
],
49+
[
50+
'/* testUnaryMinusInlineIf */',
51+
true,
52+
],
53+
[
54+
'/* testUnaryPlusInlineThen */',
55+
true,
56+
],
57+
[
58+
'/* testUnaryMinusInlineLogical */',
59+
true,
60+
],
61+
];
62+
63+
}//end dataIsUnaryPlusMinus()
64+
65+
66+
}//end class
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
<?php
2+
3+
/* testNonUnaryPlus */
4+
$a = 1 + 2;
5+
6+
/* testNonUnaryMinus */
7+
$a = 1-2;
8+
9+
/* testNonUnaryPlusArrays */
10+
$a = [1] + [2];
11+
12+
/* testUnaryPlusIntAssignment */
13+
$a = +1;
14+
15+
/* testUnaryMinusVariableAssignment */
16+
$a += -$b;
17+
18+
/* testUnaryPlusFloatAssignment */
19+
$a **= + 1.1;
20+
21+
/* testUnaryMinusBoolAssignment */
22+
$a /= -true;
23+
24+
/* testUnaryPlusStringAssignmentWithComment */
25+
$a &= + /* comment */ '1';
26+
27+
/* testUnaryMinusStringAssignment */
28+
$a .= - <<<'EOD'
29+
123
30+
EOD;
31+
32+
/* testUnaryPlusNullAssignment */
33+
$a = +null;
34+
35+
/* testUnaryMinusVariableVariableAssignment */
36+
$a .= -${$var};
37+
38+
/* testUnaryPlusIntComparison */
39+
$a = ($b === + 1);
40+
41+
/* testUnaryPlusIntComparisonYoda */
42+
$a = (+1 == $b);
43+
44+
/* testUnaryMinusFloatComparison */
45+
$a = ($b !== - 1.1);
46+
47+
/* testUnaryMinusStringComparisonYoda */
48+
$a = (-'1' != $b);
49+
50+
/* testUnaryPlusVariableLogical */
51+
$a = ($a && - $b);
52+
53+
/* testUnaryMinusVariableLogical */
54+
$a = ($a || -$b);
55+
56+
/* testUnaryMinusInlineIf */
57+
$a = $a ? -1 :
58+
/* testUnaryPlusInlineThen */
59+
+ 10;
60+
61+
/* testUnaryPlusIntReturn */
62+
return +1;
63+
64+
/* testUnaryMinusFloatReturn */
65+
return -1.1;
66+
67+
/* testUnaryPlusArrayAccess */
68+
$a = $array[ + 2 ];
69+
70+
/* testUnaryMinusStringArrayAccess */
71+
if ($line{-1} === ':') {}
72+
73+
$array = array(
74+
/* testUnaryPlusLongArrayAssignment */
75+
+1,
76+
/* testUnaryMinusLongArrayAssignmentKey */
77+
-1 =>
78+
/* testUnaryPlusLongArrayAssignmentValue */
79+
+20,
80+
);
81+
82+
$array = [
83+
/* testUnaryPlusShortArrayAssignment */
84+
+1 =>
85+
/* testNonUnaryMinusShortArrayAssignment */
86+
5-20,
87+
];
88+
89+
/* testUnaryMinusCast */
90+
$a = (bool) -2;
91+
92+
functionCall(
93+
/* testUnaryPlusFunctionCallParam */
94+
+2,
95+
/* testUnaryMinusFunctionCallParam */
96+
- 123.456,
97+
);
98+
99+
switch ($a) {
100+
/* testUnaryPlusCase */
101+
case +20:
102+
// Something.
103+
break;
104+
105+
/* testUnaryMinusCase */
106+
case -1.23:
107+
// Something.
108+
break;
109+
}
110+
111+
// Testing `$a = -+-+10`;
112+
$a =
113+
/* testSequenceNonUnary1 */
114+
-
115+
/* testSequenceNonUnary2 */
116+
+
117+
/* testSequenceNonUnary3 */
118+
-
119+
/* testSequenceUnaryEnd */
120+
+ /*comment*/ 10;
121+
122+
// Intentional parse error. This has to be the last test in the file.
123+
/* testParseError */
124+
$a = -

0 commit comments

Comments
 (0)