Skip to content

PHP 8.2 | Tokenizer, File, sniffs: account for new true type #49

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Dec 4, 2023
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
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ The file documents changes to the PHP_CodeSniffer project.
- Squiz.Commenting.FileComment
- Squiz.Commenting.InlineComment
- Thanks to Juliette Reinders Folmer (@jrfnl) for the patch
- Added support for `true` as a stand-alone type declaration
- The `File::getMethodProperties()`, `File::getMethodParameters()` and `File::getMemberProperties()` methods now all support the `true` type.
- Thanks to Juliette Reinders Folmer (@jrfnl) for the patch
- Added support for `true` as a stand-alone type to a number of sniffs
- Generic.PHP.LowerCaseType
- PSr12.Functions.NullableTypeDeclaration
- Thanks to Juliette Reinders Folmer (@jrfnl) for the patch
- Squiz.Commenting.FunctionComment: new ParamNameUnexpectedAmpersandPrefix error for parameters annotated as passed by reference while the parameter is not passed by reference
- Thanks to Dan Wallis (@fredden) for the patch
- Documentation has been added for the following sniffs:
Expand All @@ -39,6 +46,7 @@ The file documents changes to the PHP_CodeSniffer project.
- Support for PHPUnit 8 and 9 to the test suite.
- Test suites for external standards which run via the PHPCS native test suite can now run on PHPUnit 4-9 (was 4-7).
- If any of these tests use the PHPUnit `setUp()`/`tearDown()` methods or overload the `setUp()` in the `AbstractSniffUnitTest` test case, they will need to be adjusted. See the [PR details for further information](https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/59/commits/26384ebfcc0b1c1651b0e1e40c9b6c8c22881832).
- Thanks to Juliette Reinders Folmer (@jrfnl) for the patch

### Changed
- Changes have been made to the way PHPCS handles invalid sniff properties being set in a custom ruleset
Expand Down Expand Up @@ -69,6 +77,7 @@ The file documents changes to the PHP_CodeSniffer project.
- Squiz.PHP.InnerFunctions sniff no longer reports on OO methods for OO structures declared within a function or closure
- Thanks to @Daimona for the patch
- Runtime performance improvement for PHPCS CLI users. The improvement should be most noticeable for users on Windows.
- Thanks to Juliette Reinders Folmer (@jrfnl) for the patch

### Removed
- Removed support for installing via PEAR
Expand Down
3 changes: 3 additions & 0 deletions src/Files/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -1479,6 +1479,7 @@ public function getMethodParameters($stackPtr)
case T_TYPE_UNION:
case T_TYPE_INTERSECTION:
case T_FALSE:
case T_TRUE:
case T_NULL:
// Part of a type hint or default value.
if ($defaultStart === null) {
Expand Down Expand Up @@ -1705,6 +1706,7 @@ public function getMethodProperties($stackPtr)
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,
Expand Down Expand Up @@ -1906,6 +1908,7 @@ public function getMemberProperties($stackPtr)
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,
Expand Down
1 change: 1 addition & 0 deletions src/Standards/Generic/Sniffs/PHP/LowerCaseTypeSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class LowerCaseTypeSniff implements Sniff
'mixed' => true,
'static' => true,
'false' => true,
'true' => true,
'null' => true,
'never' => true,
];
Expand Down
2 changes: 2 additions & 0 deletions src/Standards/Generic/Tests/PHP/LowerCaseTypeUnitTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,5 @@ function intersectionReturnTypes ($var): \Package\ClassName&\Package\Other_Class

$arrow = fn (int $a, string $b, bool $c, array $d, Foo\Bar $e) : int => $a * $b;
$arrow = fn (Int $a, String $b, BOOL $c, Array $d, Foo\Bar $e) : Float => $a * $b;

$cl = function (False $a, TRUE $b, Null $c): ?True {}
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,5 @@ function intersectionReturnTypes ($var): \Package\ClassName&\Package\Other_Class

$arrow = fn (int $a, string $b, bool $c, array $d, Foo\Bar $e) : int => $a * $b;
$arrow = fn (int $a, string $b, bool $c, array $d, Foo\Bar $e) : float => $a * $b;

$cl = function (false $a, true $b, null $c): ?true {}
1 change: 1 addition & 0 deletions src/Standards/Generic/Tests/PHP/LowerCaseTypeUnitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public function getErrorList()
82 => 2,
85 => 1,
94 => 5,
96 => 4,
];

}//end getErrorList()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ class NullableTypeDeclarationSniff implements Sniff
T_SELF => true,
T_PARENT => true,
T_STATIC => true,
T_NULL => true,
T_FALSE => true,
T_TRUE => true,
];


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,11 @@ class testInstanceOf() {

// PHP 8.0: static return type.
function testStatic() : ? static {}

// PHP 8.2: nullable true/false.
function fooG(): ? true {}
function fooH(): ?
false {}

// Fatal error: null cannot be marked as nullable, but that's not the concern of this sniff.
function fooI(): ? null {}
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,10 @@ class testInstanceOf() {

// PHP 8.0: static return type.
function testStatic() : ?static {}

// PHP 8.2: nullable true/false.
function fooG(): ?true {}
function fooH(): ?false {}

// Fatal error: null cannot be marked as nullable, but that's not the concern of this sniff.
function fooI(): ?null {}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ protected function getErrorList()
58 => 2,
59 => 2,
87 => 1,
90 => 1,
91 => 1,
95 => 1,
];

}//end getErrorList()
Expand Down
1 change: 1 addition & 0 deletions src/Tokenizers/PHP.php
Original file line number Diff line number Diff line change
Expand Up @@ -2938,6 +2938,7 @@ protected function processAdditional()
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,
Expand Down
21 changes: 18 additions & 3 deletions tests/Core/File/GetMemberPropertiesTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,11 @@ $anon = class() {
public ?int|float $unionTypesNullable;

/* testPHP8PseudoTypeNull */
// Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method.
// PHP 8.0 - 8.1: Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method.
public null $pseudoTypeNull;

/* testPHP8PseudoTypeFalse */
// Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method.
// PHP 8.0 - 8.1: Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method.
public false $pseudoTypeFalse;

/* testPHP8PseudoTypeFalseAndBool */
Expand Down Expand Up @@ -298,7 +298,22 @@ $anon = class() {
// Intentional fatal error - types which are not allowed for intersection type, but that's not the concern of the method.
public int&string $illegalIntersectionType;

/* testPHP81NulltableIntersectionType */
/* testPHP81NullableIntersectionType */
// Intentional fatal error - nullability is not allowed with intersection type, but that's not the concern of the method.
public ?Foo&Bar $nullableIntersectionType;
};

$anon = class() {
/* testPHP82PseudoTypeTrue */
public true $pseudoTypeTrue;

/* testPHP82NullablePseudoTypeTrue */
static protected ?true $pseudoTypeNullableTrue;

/* testPHP82PseudoTypeTrueInUnion */
private int|string|true $pseudoTypeTrueInUnion;

/* testPHP82PseudoTypeFalseAndTrue */
// Intentional fatal error - Type contains both true and false, bool should be used instead, but that's not the concern of the method.
readonly true|FALSE $pseudoTypeFalseAndTrue;
};
47 changes: 46 additions & 1 deletion tests/Core/File/GetMemberPropertiesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -795,7 +795,7 @@ public function dataGetMemberProperties()
],
],
[
'/* testPHP81NulltableIntersectionType */',
'/* testPHP81NullableIntersectionType */',
[
'scope' => 'public',
'scope_specified' => true,
Expand All @@ -805,6 +805,51 @@ public function dataGetMemberProperties()
'nullable_type' => true,
],
],
[
'/* testPHP82PseudoTypeTrue */',
[
'scope' => 'public',
'scope_specified' => true,
'is_static' => false,
'is_readonly' => false,
'type' => 'true',
'nullable_type' => false,
],
],
[
'/* testPHP82NullablePseudoTypeTrue */',
[
'scope' => 'protected',
'scope_specified' => true,
'is_static' => true,
'is_readonly' => false,
'type' => '?true',
'nullable_type' => true,
],
],
[
'/* testPHP82PseudoTypeTrueInUnion */',
[
'scope' => 'private',
'scope_specified' => true,
'is_static' => false,
'is_readonly' => false,
'type' => 'int|string|true',
'nullable_type' => false,
],
],
[
'/* testPHP82PseudoTypeFalseAndTrue */',
[
'scope' => 'public',
'scope_specified' => false,
'is_static' => false,
'is_readonly' => true,
'type' => 'true|FALSE',
'nullable_type' => false,
],
],

];

}//end dataGetMemberProperties()
Expand Down
11 changes: 9 additions & 2 deletions tests/Core/File/GetMethodParametersTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ function unionTypesAllPseudoTypes(false|mixed|self|parent|iterable|Resource $var
$closure = function (?int|float $number) {};

/* testPHP8PseudoTypeNull */
// Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method.
// PHP 8.0 - 8.1: Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method.
function pseudoTypeNull(null $var = null) {}

/* testPHP8PseudoTypeFalse */
// Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method.
// PHP 8.0 - 8.1: Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method.
function pseudoTypeFalse(false $var = false) {}

/* testPHP8PseudoTypeFalseAndBool */
Expand Down Expand Up @@ -167,3 +167,10 @@ $closure = function (string&int $numeric_string) {};
/* testPHP81NullableIntersectionTypes */
// Intentional fatal error - nullability is not allowed with intersection types, but that's not the concern of the method.
$closure = function (?Foo&Bar $object) {};

/* testPHP82PseudoTypeTrue */
function pseudoTypeTrue(?true $var = true) {}

/* testPHP82PseudoTypeFalseAndTrue */
// Intentional fatal error - Type contains both true and false, bool should be used instead, but that's not the concern of the method.
function pseudoTypeFalseAndTrue(true|false $var = true) {}
48 changes: 48 additions & 0 deletions tests/Core/File/GetMethodParametersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,54 @@ public function testPHP81NullableIntersectionTypes()
}//end testPHP81NullableIntersectionTypes()


/**
* Verify recognition of PHP 8.2 stand-alone `true` type.
*
* @return void
*/
public function testPHP82PseudoTypeTrue()
{
$expected = [];
$expected[0] = [
'name' => '$var',
'content' => '?true $var = true',
'default' => 'true',
'has_attributes' => false,
'pass_by_reference' => false,
'variable_length' => false,
'type_hint' => '?true',
'nullable_type' => true,
];

$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);

}//end testPHP82PseudoTypeTrue()


/**
* Verify recognition of PHP 8.2 type declaration with (illegal) type false combined with type true.
*
* @return void
*/
public function testPHP82PseudoTypeFalseAndTrue()
{
$expected = [];
$expected[0] = [
'name' => '$var',
'content' => 'true|false $var = true',
'default' => 'true',
'has_attributes' => false,
'pass_by_reference' => false,
'variable_length' => false,
'type_hint' => 'true|false',
'nullable_type' => false,
];

$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);

}//end testPHP82PseudoTypeFalseAndTrue()


/**
* Test helper.
*
Expand Down
11 changes: 9 additions & 2 deletions tests/Core/File/GetMethodPropertiesTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,11 @@ function unionTypesAllPseudoTypes($var) : false|MIXED|self|parent|static|iterabl
$closure = function () use($a) :?int|float {};

/* testPHP8PseudoTypeNull */
// Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method.
// PHP 8.0 - 8.1: Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method.
function pseudoTypeNull(): null {}

/* testPHP8PseudoTypeFalse */
// Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method.
// PHP 8.0 - 8.1: Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method.
function pseudoTypeFalse(): false {}

/* testPHP8PseudoTypeFalseAndBool */
Expand Down Expand Up @@ -150,3 +150,10 @@ $closure = function (): string&int {};
/* testPHP81NullableIntersectionTypes */
// Intentional fatal error - nullability is not allowed with intersection types, but that's not the concern of the method.
$closure = function (): ?Foo&Bar {};

/* testPHP82PseudoTypeTrue */
function pseudoTypeTrue(): ?true {}

/* testPHP82PseudoTypeFalseAndTrue */
// Intentional fatal error - Type contains both true and false, bool should be used instead, but that's not the concern of the method.
function pseudoTypeFalseAndTrue(): true|false {}
46 changes: 46 additions & 0 deletions tests/Core/File/GetMethodPropertiesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,52 @@ public function testPHP81NullableIntersectionTypes()
}//end testPHP81NullableIntersectionTypes()


/**
* Verify recognition of PHP 8.2 stand-alone `true` type.
*
* @return void
*/
public function testPHP82PseudoTypeTrue()
{
$expected = [
'scope' => 'public',
'scope_specified' => false,
'return_type' => '?true',
'nullable_return_type' => true,
'is_abstract' => false,
'is_final' => false,
'is_static' => false,
'has_body' => true,
];

$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);

}//end testPHP82PseudoTypeTrue()


/**
* Verify recognition of PHP 8.2 type declaration with (illegal) type false combined with type true.
*
* @return void
*/
public function testPHP82PseudoTypeFalseAndTrue()
{
$expected = [
'scope' => 'public',
'scope_specified' => false,
'return_type' => 'true|false',
'nullable_return_type' => false,
'is_abstract' => false,
'is_final' => false,
'is_static' => false,
'has_body' => true,
];

$this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected);

}//end testPHP82PseudoTypeFalseAndTrue()


/**
* Test helper.
*
Expand Down
Loading