Skip to content

Commit

Permalink
Merge pull request #49 from PHPCSStandards/php-8.2/account-for-true-type
Browse files Browse the repository at this point in the history
PHP 8.2 | Tokenizer, File, sniffs: account for new `true` type
  • Loading branch information
jrfnl authored Dec 4, 2023
2 parents 2ff6414 + ef96fc6 commit 26df2fc
Show file tree
Hide file tree
Showing 19 changed files with 228 additions and 8 deletions.
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

0 comments on commit 26df2fc

Please sign in to comment.