Skip to content

Commit

Permalink
Universal/ConstructorDestructorReturn: add auto-fixer for return type
Browse files Browse the repository at this point in the history
The "returns a value" warning cannot be auto-fixed as it should be looked at by a developer. However, the "return type found" error _can_ be auto-fixed, so let's do so.
  • Loading branch information
jrfnl committed Oct 26, 2022
1 parent 2c8c618 commit 92f65a5
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 2 deletions.
15 changes: 13 additions & 2 deletions Universal/Sniffs/CodeAnalysis/ConstructorDestructorReturnSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,22 +87,33 @@ public function process(File $phpcsFile, $stackPtr)
*/

// Check for a return type.
$tokens = $phpcsFile->getTokens();
$properties = FunctionDeclarations::getProperties($phpcsFile, $stackPtr);
if ($properties['return_type'] !== '' && $properties['return_type_token'] !== false) {
$data = [
$functionType,
$properties['return_type'],
];

$phpcsFile->addError(
$fix = $phpcsFile->addFixableError(
'%s can not declare a return type. Found: %s',
$properties['return_type_token'],
'ReturnTypeFound',
$data
);

if ($fix === true) {
$phpcsFile->fixer->beginChangeset();

$parensCloser = $tokens[$stackPtr]['parenthesis_closer'];
for ($i = ($parensCloser + 1); $i <= $properties['return_type_end_token']; $i++) {
$phpcsFile->fixer->replaceToken($i, '');
}

$phpcsFile->fixer->endChangeset();
}
}

$tokens = $phpcsFile->getTokens();
if (isset($tokens[$stackPtr]['scope_opener'], $tokens[$stackPtr]['scope_closer']) === false) {
// Abstract/interface method, live coding or parse error.
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<?php

/*
* OK.
*/

// Global function, not a constructor/destructor.
function __construct() : int {
return 123;
}

function __destruct() : float {
return 321;
}

// Methods which are not constructors can be disregarded.
class NotAConstructor {
public function __set($name, $value): void {
// Do something.
}

public function Foo(): void {
// Do something.
}

public function Bar() {
return $this;
}
}

// Constructor/Destructor without a return statement or return type.
class NoReturn {
protected function __construct()
{
// Do something.
}

protected function __destruct()
{
// Do something.
}

// Also applies to PHP4-style constructors/destructors.
function NoReturn()
{
// Do something.
}

function _NoReturn()
{
// Do something.
}
}

// Constructor/Destructor with return statement, but no value.
$anon = new class extends ReturnNoValue {
public function __construct() {
if ($foo) {
return ;
} else {
return /* comments are fine */
// Even when spread over multiple lines.
;
}

return;
}

public function __destruct() {
// Do something.
return;
}

// Non-constructor/destructor method returning.
public function returnsavalue() {
return 'php4style';
}
};


/*
* Not OK.
*/
class ReturnsAValue {
public function __construct() {
return $this;
}

public function __destruct() {
return 'destructed';
}

function returnsavalue()
{
return 'php4style';
}
}

$anon = new class() extends ReturnsAValue {
public function __Construct()
{
return $this;
}

public function __deStRucT() {
return 'destructed';
}
};

/*
* Return types are not allowed on constructor/destructor methods (fatal error).
*/

trait AbstractConstructorDestructorReturnTypes {
abstract public function __construct();

abstract public function __destruct();
}

interface InterfaceMethodReturnTypes {
public function __construct();

public function __destruct();
}

0 comments on commit 92f65a5

Please sign in to comment.