Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
5cca22d
Util/Tokens: introduce new `$nameTokens` array
jrfnl Apr 6, 2025
e71ecf8
PHP 8.0 | Tokenizer/PHP: namespaced names as single token
jrfnl Jul 7, 2020
11afb05
Tokenizer/PHP: update union/intersection/DNF type token tokenization …
jrfnl Apr 5, 2025
434ef2f
Tokenizer/PHP: update the arrow function backfill to allow for PHP 8 …
jrfnl Sep 1, 2020
692580b
Tokenizer/PHP: update the short array tokenization to allow for PHP 8…
jrfnl Nov 2, 2020
a152c9d
Tokenizer/PHP: update various tests to allow for PHP 8 identifier tokens
jrfnl Apr 8, 2025
dfcd0bd
File::getMethodParameters(): fix method to work with the PHP 8 identi…
jrfnl Aug 31, 2020
c5b6795
File::getMethodProperties(): fix method to work with the PHP 8 identi…
jrfnl Aug 31, 2020
c454092
File::getMemberProperties(): fix method to work with the PHP 8 identi…
jrfnl Aug 31, 2020
579cb91
File::isReference(): fix method to work with the PHP 8 identifier tokens
jrfnl Aug 31, 2020
b2d9194
File::findExtendedClassName(): fix method to work with the PHP 8 iden…
jrfnl Aug 31, 2020
0283b77
File::findImplementedInterfaceNames(): fix method to work with the PH…
jrfnl Aug 31, 2020
599f885
File::find[Start|End]OfStatement(): update tests to allow for PHP 8 i…
jrfnl Aug 31, 2020
9f7a0a6
File::getTokenAsString(): update tests to allow for PHP 8 identifier …
jrfnl Apr 6, 2025
6c6fd3d
Tokens::$functionNameTokens: add the new PHP 8 identifier name tokens
jrfnl Sep 2, 2020
3e405f9
Generic/DuplicateClassName: fix sniff to work with the PHP 8 identifi…
jrfnl Aug 31, 2020
b241905
Generic/ForLoopWithTestFunctionCall: fix sniff to work with the PHP 8…
jrfnl Apr 8, 2025
21298f6
Generic/DisallowYodaConditions: fix sniff to work with the PHP 8 iden…
jrfnl Apr 8, 2025
187c7d8
Generic/FunctionCallArgumentSpacing: fix sniff to work with the PHP 8…
jrfnl Apr 8, 2025
b09b045
Generic/UpperCaseConstantName: fix sniff to work with the PHP 8 ident…
jrfnl Apr 8, 2025
3a3f9d1
Generic/ForbiddenFunctions: fix sniff to work with the PHP 8 identifi…
jrfnl Aug 31, 2020
0c853ad
Generic/SAPIUsage: fix sniff to work with the PHP 8 identifier tokens
jrfnl Apr 8, 2025
66552e5
Generic/IncrementDecrementSpacing: fix sniff to work with the PHP 8 i…
jrfnl Apr 8, 2025
bd9d3f0
Generic/LanguageConstructSpacing: fix sniff to work with the PHP 8 id…
jrfnl Aug 31, 2020
894c5d9
PEAR/MultiLineCondition: fix sniff to work with the PHP 8 identifier …
jrfnl Apr 8, 2025
e9f74a6
PSR1/SideEffects: fix sniff to work with the PHP 8 identifier tokens
jrfnl Apr 8, 2025
0f1c898
PSR2/ClassDeclaration: fix sniff to work with the PHP 8 identifier to…
jrfnl Sep 1, 2020
bb933e9
PSR12/ClassInstantiation: fix sniff to work with the PHP 8 identifier…
jrfnl Aug 31, 2020
bbded9b
PSR12/ImportStatement: fix sniff to work with the PHP 8 identifier to…
jrfnl Aug 31, 2020
d70c2a4
PSR12/NullableTypeDeclaration: fix sniff to work with the PHP 8 ident…
jrfnl Aug 31, 2020
2017437
PSR12/CompoundNamespaceDepth: fix sniff to work with the PHP 8 identi…
jrfnl Aug 31, 2020
2ccfae2
Squiz/SelfMemberReference: fix sniff to work with the PHP 8 identifie…
jrfnl Sep 1, 2020
1529566
Squiz/FunctionCommentThrowTag: fix sniff to work with the PHP 8 ident…
jrfnl Apr 7, 2025
21a7d14
Squiz/VariableComment: fix sniff to work with the PHP 8 identifier to…
jrfnl Sep 1, 2020
6e33f43
Squiz/OperatorBracket: fix sniff to work with the PHP 8 identifier to…
jrfnl Apr 6, 2025
71c8de2
Squiz/DisallowComparisonAssignment: fix sniff to work with the PHP 8 …
jrfnl Apr 8, 2025
7a921cd
Squiz/DisallowMultipleAssignments: fix sniff to work with the PHP 8 i…
jrfnl Sep 1, 2020
f80aeb3
Squiz/DisallowSizeFunctionsInLoops: fix sniff to work with the PHP 8 …
jrfnl Apr 8, 2025
24c5688
Squiz/LowercasePHPFunctions: fix sniff to work with the PHP 8 identif…
jrfnl Aug 31, 2020
459f971
PEAR/FunctionCallSignature: add tests with the PHP 8 identifier tokens
jrfnl Sep 2, 2020
121c58c
PSR2/NamespaceDeclaration: remove redundant condition
jrfnl Apr 7, 2025
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
37 changes: 14 additions & 23 deletions src/Files/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -1415,7 +1415,10 @@ public function getMethodParameters($stackPtr)
}
break;
case T_STRING:
// This is a string, so it may be a type hint, but it could
case T_NAME_QUALIFIED:
case T_NAME_FULLY_QUALIFIED:
case T_NAME_RELATIVE:
// This is an identifier name, so it may be a type declaration, but it could
// also be a constant used as a default value.
$prevComma = false;
for ($t = $i; $t >= $opener; $t--) {
Expand Down Expand Up @@ -1673,17 +1676,15 @@ public function getMethodProperties($stackPtr)
$scopeOpener = $this->tokens[$stackPtr]['scope_opener'];
}

$valid = [
T_STRING => T_STRING,
$valid = Tokens::$nameTokens;
$valid += [
T_CALLABLE => T_CALLABLE,
T_SELF => T_SELF,
T_PARENT => T_PARENT,
T_STATIC => T_STATIC,
T_FALSE => T_FALSE,
T_TRUE => T_TRUE,
T_NULL => T_NULL,
T_NAMESPACE => T_NAMESPACE,
T_NS_SEPARATOR => T_NS_SEPARATOR,
T_TYPE_UNION => T_TYPE_UNION,
T_TYPE_INTERSECTION => T_TYPE_INTERSECTION,
T_TYPE_OPEN_PARENTHESIS => T_TYPE_OPEN_PARENTHESIS,
Expand Down Expand Up @@ -1876,16 +1877,14 @@ public function getMemberProperties($stackPtr)

if ($i < $stackPtr) {
// We've found a type.
$valid = [
T_STRING => T_STRING,
$valid = Tokens::$nameTokens;
$valid += [
T_CALLABLE => T_CALLABLE,
T_SELF => T_SELF,
T_PARENT => T_PARENT,
T_FALSE => T_FALSE,
T_TRUE => T_TRUE,
T_NULL => T_NULL,
T_NAMESPACE => T_NAMESPACE,
T_NS_SEPARATOR => T_NS_SEPARATOR,
T_TYPE_UNION => T_TYPE_UNION,
T_TYPE_INTERSECTION => T_TYPE_INTERSECTION,
T_TYPE_OPEN_PARENTHESIS => T_TYPE_OPEN_PARENTHESIS,
Expand Down Expand Up @@ -2086,12 +2085,10 @@ public function isReference($stackPtr)
return true;
} else {
$skip = Tokens::$emptyTokens;
$skip[] = T_NS_SEPARATOR;
$skip += Tokens::$nameTokens;
$skip[] = T_SELF;
$skip[] = T_PARENT;
$skip[] = T_STATIC;
$skip[] = T_STRING;
$skip[] = T_NAMESPACE;
$skip[] = T_DOUBLE_COLON;

$nextSignificantAfter = $this->findNext(
Expand Down Expand Up @@ -2781,11 +2778,8 @@ public function findExtendedClassName($stackPtr)
return false;
}

$find = [
T_NS_SEPARATOR,
T_STRING,
T_WHITESPACE,
];
$find = Tokens::$nameTokens;
$find[] = T_WHITESPACE;

$end = $this->findNext($find, ($extendsIndex + 1), ($classOpenerIndex + 1), true);
$name = $this->getTokensAsString(($extendsIndex + 1), ($end - $extendsIndex - 1));
Expand Down Expand Up @@ -2833,12 +2827,9 @@ public function findImplementedInterfaceNames($stackPtr)
return false;
}

$find = [
T_NS_SEPARATOR,
T_STRING,
T_WHITESPACE,
T_COMMA,
];
$find = Tokens::$nameTokens;
$find[] = T_WHITESPACE;
$find[] = T_COMMA;

$end = $this->findNext($find, ($implementsIndex + 1), ($classOpenerIndex + 1), true);
$name = $this->getTokensAsString(($implementsIndex + 1), ($end - $implementsIndex - 1));
Expand Down
24 changes: 8 additions & 16 deletions src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,24 +63,16 @@ public function process(File $phpcsFile, $stackPtr)
// Keep track of what namespace we are in.
if ($tokens[$stackPtr]['code'] === T_NAMESPACE) {
$nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true);
if ($nextNonEmpty !== false
// Ignore namespace keyword used as operator.
&& $tokens[$nextNonEmpty]['code'] !== T_NS_SEPARATOR
) {
$namespace = '';
for ($i = $nextNonEmpty; $i < $phpcsFile->numTokens; $i++) {
if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) {
continue;
}

if ($tokens[$i]['code'] !== T_STRING && $tokens[$i]['code'] !== T_NS_SEPARATOR) {
break;
}

$namespace .= $tokens[$i]['content'];
if ($nextNonEmpty !== false) {
if ($tokens[$nextNonEmpty]['code'] === T_STRING
|| $tokens[$nextNonEmpty]['code'] === T_NAME_QUALIFIED
) {
$namespace = $tokens[$nextNonEmpty]['content'];
} else if ($tokens[$nextNonEmpty]['code'] === T_OPEN_CURLY_BRACKET) {
$namespace = '';
}

$stackPtr = $i;
$stackPtr = $nextNonEmpty;
}
} else {
$name = $phpcsFile->getDeclarationName($stackPtr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public function process(File $phpcsFile, $stackPtr)
continue;
} else if ($position > 1) {
break;
} else if ($code !== T_VARIABLE && $code !== T_STRING) {
} else if ($code !== T_VARIABLE && isset(Tokens::$nameTokens[$code]) === false) {
continue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public function process(File $phpcsFile, $stackPtr)
);

if ($beforeOpeningParenthesisIndex === false || $tokens[$beforeOpeningParenthesisIndex]['code'] !== T_ARRAY) {
if ($tokens[$beforeOpeningParenthesisIndex]['code'] === T_STRING) {
if (isset(Tokens::$nameTokens[$tokens[$beforeOpeningParenthesisIndex]['code']]) === true) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@ class FunctionCallArgumentSpacingSniff implements Sniff
*/
public function register()
{
return[
T_STRING,
T_ISSET,
T_UNSET,
T_SELF,
T_STATIC,
T_PARENT,
T_VARIABLE,
T_CLOSE_CURLY_BRACKET,
T_CLOSE_PARENTHESIS,
];
$targets = Tokens::$nameTokens;
$targets[] = T_ISSET;
$targets[] = T_UNSET;
$targets[] = T_SELF;
$targets[] = T_STATIC;
$targets[] = T_PARENT;
$targets[] = T_VARIABLE;
$targets[] = T_CLOSE_CURLY_BRACKET;
$targets[] = T_CLOSE_PARENTHESIS;

return $targets;

}//end register()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public function register()
{
return [
T_STRING,
T_NAME_FULLY_QUALIFIED,
T_CONST,
];

Expand Down Expand Up @@ -83,7 +84,7 @@ public function process(File $phpcsFile, $stackPtr)
}//end if

// Only interested in define statements now.
if (strtolower($tokens[$stackPtr]['content']) !== 'define') {
if (strtolower(ltrim($tokens[$stackPtr]['content'], '\\')) !== 'define') {
return;
}

Expand Down
32 changes: 16 additions & 16 deletions src/Standards/Generic/Sniffs/PHP/ForbiddenFunctionsSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ public function register()
$this->forbiddenFunctionNames[$i] = '/'.$name.'/i';
}

return [T_STRING];
return [
T_STRING,
T_NAME_FULLY_QUALIFIED,
];
}

// If we are not pattern matching, we need to work out what
Expand Down Expand Up @@ -102,7 +105,10 @@ public function register()
$this->forbiddenFunctionNames = array_map('strtolower', $this->forbiddenFunctionNames);
$this->forbiddenFunctions = array_combine($this->forbiddenFunctionNames, $this->forbiddenFunctions);

return array_unique($register);
$targets = array_unique($register);
$targets[] = T_NAME_FULLY_QUALIFIED;

return $targets;

}//end register()

Expand Down Expand Up @@ -132,22 +138,11 @@ public function process(File $phpcsFile, $stackPtr)
T_AS => true,
T_NEW => true,
T_INSTEADOF => true,
T_NS_SEPARATOR => true,
T_IMPLEMENTS => true,
];

$prevToken = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true);

// If function call is directly preceded by a NS_SEPARATOR it points to the
// global namespace, so we should still catch it.
if ($tokens[$prevToken]['code'] === T_NS_SEPARATOR) {
$prevToken = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($prevToken - 1), null, true);
if ($tokens[$prevToken]['code'] === T_STRING) {
// Not in the global namespace.
return;
}
}

if (isset($ignore[$tokens[$prevToken]['code']]) === true) {
// Not a call to a PHP function.
return;
Expand All @@ -159,7 +154,9 @@ public function process(File $phpcsFile, $stackPtr)
return;
}

if ($tokens[$stackPtr]['code'] === T_STRING && $tokens[$nextToken]['code'] !== T_OPEN_PARENTHESIS) {
if (($tokens[$stackPtr]['code'] === T_STRING || $tokens[$stackPtr]['code'] === T_NAME_FULLY_QUALIFIED)
&& $tokens[$nextToken]['code'] !== T_OPEN_PARENTHESIS
) {
// Not a call to a PHP function.
return;
}
Expand All @@ -170,8 +167,11 @@ public function process(File $phpcsFile, $stackPtr)
}

$function = strtolower($tokens[$stackPtr]['content']);
$pattern = null;
if ($tokens[$stackPtr]['code'] === T_NAME_FULLY_QUALIFIED) {
$function = ltrim($function, '\\');
}

$pattern = null;
if ($this->patternMatch === true) {
$count = 0;
$pattern = preg_replace(
Expand All @@ -194,7 +194,7 @@ public function process(File $phpcsFile, $stackPtr)
}
}//end if

$this->addError($phpcsFile, $stackPtr, $tokens[$stackPtr]['content'], $pattern);
$this->addError($phpcsFile, $stackPtr, $function, $pattern);

}//end process()

Expand Down
17 changes: 11 additions & 6 deletions src/Standards/Generic/Sniffs/PHP/SAPIUsageSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ class SAPIUsageSniff implements Sniff
*/
public function register()
{
return [T_STRING];
return [
T_STRING,
T_NAME_FULLY_QUALIFIED,
];

}//end register()

Expand All @@ -41,6 +44,11 @@ public function process(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();

$function = strtolower(ltrim($tokens[$stackPtr]['content'], '\\'));
if ($function !== 'php_sapi_name') {
return;
}

$ignore = [
T_DOUBLE_COLON => true,
T_OBJECT_OPERATOR => true,
Expand All @@ -55,11 +63,8 @@ public function process(File $phpcsFile, $stackPtr)
return;
}

$function = strtolower($tokens[$stackPtr]['content']);
if ($function === 'php_sapi_name') {
$error = 'Use the PHP_SAPI constant instead of calling php_sapi_name()';
$phpcsFile->addError($error, $stackPtr, 'FunctionFound');
}
$error = 'Use the PHP_SAPI constant instead of calling php_sapi_name()';
$phpcsFile->addError($error, $stackPtr, 'FunctionFound');

}//end process()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ public function process(File $phpcsFile, $stackPtr)
// Is this a pre-increment/decrement ?
$nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true);
if ($nextNonEmpty !== false
&& ($tokens[$nextNonEmpty]['code'] === T_VARIABLE || $tokens[$nextNonEmpty]['code'] === T_STRING)
&& ($tokens[$nextNonEmpty]['code'] === T_VARIABLE
|| isset(Tokens::$nameTokens[$tokens[$nextNonEmpty]['code']]) === true)
) {
if ($nextNonEmpty === ($stackPtr + 1)) {
$phpcsFile->recordMetric($stackPtr, 'Spacing between in/decrementor and variable', 0);
Expand Down Expand Up @@ -106,7 +107,7 @@ public function process(File $phpcsFile, $stackPtr)
$prevNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true);
if ($prevNonEmpty !== false
&& ($tokens[$prevNonEmpty]['code'] === T_VARIABLE
|| $tokens[$prevNonEmpty]['code'] === T_STRING
|| isset(Tokens::$nameTokens[$tokens[$prevNonEmpty]['code']]) === true
|| $tokens[$prevNonEmpty]['code'] === T_CLOSE_SQUARE_BRACKET)
) {
if ($prevNonEmpty === ($stackPtr - 1)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,9 @@ public function process(File $phpcsFile, $stackPtr)
$content = $tokens[$stackPtr]['content'];
if ($tokens[$stackPtr]['code'] === T_NAMESPACE) {
$nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true);
if ($nextNonEmpty !== false && $tokens[$nextNonEmpty]['code'] === T_NS_SEPARATOR) {
if ($nextNonEmpty !== false && $tokens[$nextNonEmpty]['code'] === T_NAME_FULLY_QUALIFIED) {
// Namespace keyword used as operator, not as the language construct.
// Note: in PHP >= 8 namespaced names no longer allow for whitespace/comments between the parts (parse error).
return;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ namespace Foo\Bar;
class MyClass {}
interface YourInterface {}

namespace Foo /*comment*/ \ /*comment*/ Bar;
namespace /*comment*/ Foo\Bar;
class MyClass {}
interface YourInterface {}
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,7 @@ endfor;
for ($i = 0; $i < 10; $i = increment($i)) {}

for ($i = initialValue(); $i < 10; $i = increment($i)) {}

for ($i = 0; \Fully\qualified($value); $i++) {}
for ($i = 0; Partially\qualified($value); $i++) {}
for ($i = 0; namespace\relatived($value); $i++) {}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ public function getWarningList($testFile='')
66 => 1,
72 => 1,
81 => 1,
97 => 1,
98 => 1,
99 => 1,
];
default:
return [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,10 @@ echo match ($text) {
1 >= $value;
1 <= $value;
1 <=> $value;

if(\Fully\qualified('foo') === false){}
if(true === \Fully\qualified(10)){}
if(Partially\qualified('foo') === 10){}
if(1.5 === Partially\qualified(true)){}
if(namespace\relative(false) === null){}
if('string' === namespace\relative(null)){}
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ public function getErrorList()
185 => 1,
186 => 1,
187 => 1,
190 => 1,
192 => 1,
194 => 1,
];

}//end getErrorList()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,7 @@ $foobar = functionCallMatchParam(
} , // But check the spacing again once the match expression has finished.
$args
);

$result = \Fully\qualified($arg1,$arg2);
$result = Partially\qualified($arg1 , $arg2);
$result = namespace\relative($arg1 , $arg2);
Loading