Unverified Commit ece56b49 authored by jrfnl's avatar jrfnl
Browse files

PHP 8.1 | ForbiddenNames: detect reserved keywords used as name for an enum

As enums are a new type of OO structure, this means that reserved keywords are not allowed to be used as a name for these structures.

This updates the `ForbiddenNames` sniff to start sniffing enum declarations for forbidden names as well.

Includes:
* Adding `enum` and `backed-enum` cases to the test case file generator to allow for auto-generating the test case files.
* Adding the actual (generated) test case files.
* Handling a very very specific tokenizer edge case, which I don't think PHPCS should need to account for.
* Adding an additional test case to the `ForbiddenNamesUnitTest.2.inc` file to cover a specific condition in the code to handle the tokenizer edge case.
parent f72a92fe
......@@ -210,6 +210,7 @@ class ForbiddenNamesSniff extends Sniff
\T_CLASS,
\T_INTERFACE,
\T_TRAIT,
\T_ENUM,
\T_FUNCTION,
\T_CONST,
\T_STRING, // Function calls to `define()`.
......@@ -258,6 +259,7 @@ class ForbiddenNamesSniff extends Sniff
case 'T_CLASS':
case 'T_INTERFACE':
case 'T_TRAIT':
case 'T_ENUM':
$this->processOODeclaration($phpcsFile, $stackPtr);
return;
......@@ -270,6 +272,31 @@ class ForbiddenNamesSniff extends Sniff
return;
case 'T_STRING':
/*
* Handle a very specific edge case `enum extends/implements`, where PHP itself does not
* correctly tokenize the keyword and considering this is a pretty awkward parse error,
* we can't expect PHPCS to handle this.
*/
if (\strtolower($tokens[$stackPtr]['content']) === 'enum') {
$nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true);
if ($nextNonEmpty === false) {
return;
}
$nextNonEmptyLC = \strtolower($tokens[$nextNonEmpty]['content']);
if ($nextNonEmptyLC === 'extends' || $nextNonEmptyLC === 'implements') {
$this->checkName($phpcsFile, $stackPtr, $tokens[$nextNonEmpty]['content']);
$this->checkOtherName(
$phpcsFile,
$stackPtr,
$tokens[$nextNonEmpty]['content'],
$tokens[$stackPtr]['content'] . ' declaration'
);
}
return;
}
$this->processString($phpcsFile, $stackPtr);
return;
......
<?php
enum Baz: string {}
enum Abstract: string {}
enum And: string {}
enum Array: string {}
enum As: string {}
enum Break: string {}
enum Callable: string {}
enum Case: string {}
enum Catch: string {}
enum Class: string {}
enum Clone: string {}
enum Const: string {}
enum Continue: string {}
enum Declare: string {}
enum Default: string {}
enum Die: string {}
enum Do: string {}
enum Echo: string {}
enum Else: string {}
enum Elseif: string {}
enum Empty: string {}
enum Enddeclare: string {}
enum Endfor: string {}
enum Endforeach: string {}
enum Endif: string {}
enum Endswitch: string {}
enum Endwhile: string {}
enum Eval: string {}
enum Exit: string {}
enum Extends: string {}
enum Final: string {}
enum Finally: string {}
enum Fn: string {}
enum For: string {}
enum Foreach: string {}
enum Function: string {}
enum Global: string {}
enum Goto: string {}
enum If: string {}
enum Implements: string {}
enum Include: string {}
enum Include_once: string {}
enum Instanceof: string {}
enum Insteadof: string {}
enum Interface: string {}
enum Isset: string {}
enum List: string {}
enum Namespace: string {}
enum New: string {}
enum Or: string {}
enum Print: string {}
enum Private: string {}
enum Protected: string {}
enum Public: string {}
enum Require: string {}
enum Require_once: string {}
enum Return: string {}
enum Static: string {}
enum Switch: string {}
enum Throw: string {}
enum Trait: string {}
enum Try: string {}
enum Unset: string {}
enum Use: string {}
enum Var: string {}
enum While: string {}
enum Xor: string {}
enum Yield: string {}
enum __CLASS__: string {}
enum __DIR__: string {}
enum __FILE__: string {}
enum __FUNCTION__: string {}
enum __LINE__: string {}
enum __METHOD__: string {}
enum __NAMESPACE__: string {}
enum __TRAIT__: string {}
enum Null: string {}
enum True: string {}
enum False: string {}
enum Bool: string {}
enum Int: string {}
enum Float: string {}
enum String: string {}
enum Iterable: string {}
enum Void: string {}
enum Object: string {}
enum Resource: string {}
enum Mixed: string {}
enum Numeric: string {}
<?php
enum Baz {}
enum Abstract {}
enum And {}
enum Array {}
enum As {}
enum Break {}
enum Callable {}
enum Case {}
enum Catch {}
enum Class {}
enum Clone {}
enum Const {}
enum Continue {}
enum Declare {}
enum Default {}
enum Die {}
enum Do {}
enum Echo {}
enum Else {}
enum Elseif {}
enum Empty {}
enum Enddeclare {}
enum Endfor {}
enum Endforeach {}
enum Endif {}
enum Endswitch {}
enum Endwhile {}
enum Eval {}
enum Exit {}
enum Extends {}
enum Final {}
enum Finally {}
enum Fn {}
enum For {}
enum Foreach {}
enum Function {}
enum Global {}
enum Goto {}
enum If {}
enum Implements {}
enum Include {}
enum Include_once {}
enum Instanceof {}
enum Insteadof {}
enum Interface {}
enum Isset {}
enum List {}
enum Namespace {}
enum New {}
enum Or {}
enum Print {}
enum Private {}
enum Protected {}
enum Public {}
enum Require {}
enum Require_once {}
enum Return {}
enum Static {}
enum Switch {}
enum Throw {}
enum Trait {}
enum Try {}
enum Unset {}
enum Use {}
enum Var {}
enum While {}
enum Xor {}
enum Yield {}
enum __CLASS__ {}
enum __DIR__ {}
enum __FILE__ {}
enum __FUNCTION__ {}
enum __LINE__ {}
enum __METHOD__ {}
enum __NAMESPACE__ {}
enum __TRAIT__ {}
enum Null {}
enum True {}
enum False {}
enum Bool {}
enum Int {}
enum Float {}
enum String {}
enum Iterable {}
enum Void {}
enum Object {}
enum Resource {}
enum Mixed {}
enum Numeric {}
......@@ -41,3 +41,8 @@ class Foo extends List implements Callable
interface Bar extends Yield {}
$anon = new class extends Clone {};
// Live coding/parse error.
// This has to be the last test in the file.
// Testing T_STRING without anything after it.
someText
......@@ -55,6 +55,8 @@ class ForbiddenNamesUnitTest extends BaseSniffTest
'class' => true,
'interface' => true,
'trait' => true,
'enum' => true,
'backed-enum' => true,
// Aliases.
'use-as' => true,
......@@ -123,6 +125,8 @@ class ForbiddenNamesUnitTest extends BaseSniffTest
'class',
'interface',
'trait',
'enum',
'backed-enum',
'function-declare',
'const',
'define',
......
......@@ -120,6 +120,8 @@ $testsForOtherInvalidNames = [
'class' => true,
'interface' => true,
'trait' => true,
'enum' => true,
'backed-enum' => true,
// Aliases.
'use-as' => true,
......@@ -157,6 +159,14 @@ $tests = [
$name = ucfirst($name);
return "trait $name {}\n";
},
'enum' => function ($name) {
$name = ucfirst($name);
return "enum $name {}\n";
},
'backed-enum' => function ($name) {
$name = ucfirst($name);
return "enum $name: string {}\n";
},
'function-declare' => function ($name) {
return "function $name() { }\n";
},
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment