Skip to content

Commit

Permalink
PHP 8.0 | Generic/LowerCaseType: refactor [3] - allow for union types
Browse files Browse the repository at this point in the history
Allow for union types, as introduced in PHP 8.0, in return and parameter type declarations.

Includes unit tests.
  • Loading branch information
jrfnl committed Nov 2, 2020
1 parent 4c92103 commit b4313a7
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 13 deletions.
88 changes: 75 additions & 13 deletions src/Standards/Generic/Sniffs/PHP/LowerCaseTypeSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,23 @@ public function process(File $phpcsFile, $stackPtr)
$props = $phpcsFile->getMethodProperties($stackPtr);

// Strip off potential nullable indication.
$returnType = ltrim($props['return_type'], '?');
$returnTypeLower = strtolower($returnType);
$returnType = ltrim($props['return_type'], '?');

if ($returnType !== ''
&& isset($this->phpTypes[$returnTypeLower]) === true
) {
if ($returnType !== '') {
$error = 'PHP return type declarations must be lowercase; expected "%s" but found "%s"';
$errorCode = 'ReturnTypeFound';

$this->processType($phpcsFile, $props['return_type_token'], $returnType, $error, $errorCode);
if (strpos($returnType, '|') !== false) {
$this->processUnionType(
$phpcsFile,
$props['return_type_token'],
$props['return_type_end_token'],
$error,
$errorCode
);
} else if (isset($this->phpTypes[strtolower($returnType)]) === true) {
$this->processType($phpcsFile, $props['return_type_token'], $returnType, $error, $errorCode);
}
}

/*
Expand All @@ -111,22 +118,77 @@ public function process(File $phpcsFile, $stackPtr)

foreach ($params as $param) {
// Strip off potential nullable indication.
$typeHint = ltrim($param['type_hint'], '?');
$typeHintLower = strtolower($typeHint);
$typeHint = ltrim($param['type_hint'], '?');

if ($typeHint !== ''
&& isset($this->phpTypes[$typeHintLower]) === true
) {
if ($typeHint !== '') {
$error = 'PHP parameter type declarations must be lowercase; expected "%s" but found "%s"';
$errorCode = 'ParamTypeFound';

$this->processType($phpcsFile, $param['type_hint_token'], $typeHint, $error, $errorCode);
if (strpos($typeHint, '|') !== false) {
$this->processUnionType(
$phpcsFile,
$param['type_hint_token'],
$param['type_hint_end_token'],
$error,
$errorCode
);
} else if (isset($this->phpTypes[strtolower($typeHint)]) === true) {
$this->processType($phpcsFile, $param['type_hint_token'], $typeHint, $error, $errorCode);
}
}
}
}//end foreach

}//end process()


/**
* Processes a union type declaration.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param int $typeDeclStart The position of the start of the type token.
* @param int $typeDeclEnd The position of the end of the type token.
* @param string $error Error message template.
* @param string $errorCode The error code.
*
* @return void
*/
protected function processUnionType(File $phpcsFile, $typeDeclStart, $typeDeclEnd, $error, $errorCode)
{
$tokens = $phpcsFile->getTokens();
$current = $typeDeclStart;

do {
$endOfType = $phpcsFile->findNext(T_TYPE_UNION, $current, $typeDeclEnd);
if ($endOfType === false) {
// This must be the last type in the union.
$endOfType = ($typeDeclEnd + 1);
}

$hasNsSep = $phpcsFile->findNext(T_NS_SEPARATOR, $current, $endOfType);
if ($hasNsSep !== false) {
// Multi-token class based type. Ignore.
$current = ($endOfType + 1);
continue;
}

// Type consisting of a single token.
$startOfType = $phpcsFile->findNext(Tokens::$emptyTokens, $current, $endOfType, true);
if ($startOfType === false) {
// Parse error.
return;
}

$type = $tokens[$startOfType]['content'];
if (isset($this->phpTypes[strtolower($type)]) === true) {
$this->processType($phpcsFile, $startOfType, $type, $error, $errorCode);
}

$current = ($endOfType + 1);
} while ($current <= $typeDeclEnd);

}//end processUnionType()


/**
* Processes a type cast or a singular type declaration.
*
Expand Down
8 changes: 8 additions & 0 deletions src/Standards/Generic/Tests/PHP/LowerCaseTypeUnitTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,11 @@ $foo = function (?Int $a, ? Callable $b)

$var = (BInARY) $string;
$var = (binary)$string;

function unionParamTypesA (bool|array| /* nullability operator not allowed in union */ NULL $var) {}

function unionParamTypesB (\Package\ClassName | Int | \Package\Other_Class | FALSE $var) {}

function unionReturnTypesA ($var): bool|array| /* nullability operator not allowed in union */ NULL {}

function unionReturnTypesB ($var): \Package\ClassName | Int | \Package\Other_Class | FALSE {}
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,11 @@ $foo = function (?int $a, ? callable $b)

$var = (binary) $string;
$var = (binary)$string;

function unionParamTypesA (bool|array| /* nullability operator not allowed in union */ null $var) {}

function unionParamTypesB (\Package\ClassName | int | \Package\Other_Class | false $var) {}

function unionReturnTypesA ($var): bool|array| /* nullability operator not allowed in union */ null {}

function unionReturnTypesB ($var): \Package\ClassName | int | \Package\Other_Class | false {}
4 changes: 4 additions & 0 deletions src/Standards/Generic/Tests/PHP/LowerCaseTypeUnitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ public function getErrorList()
43 => 2,
44 => 1,
46 => 1,
49 => 1,
51 => 2,
53 => 1,
55 => 2,
];

}//end getErrorList()
Expand Down

0 comments on commit b4313a7

Please sign in to comment.