Skip to content

Commit

Permalink
Added PSR12.Classes.AnonClassDeclaration sniff to enforce formatting …
Browse files Browse the repository at this point in the history
…of anon classes

Includes refactoring and some message wording changes to other sniffs as the anon class sniff makes use of several others
  • Loading branch information
gsherwood committed Sep 16, 2019
1 parent 7a46d7b commit b770ed3
Show file tree
Hide file tree
Showing 10 changed files with 665 additions and 108 deletions.
6 changes: 6 additions & 0 deletions package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
-- Thanks to Mponos George for the contribution
- Added Generic.PHP.RequireStrictTypes sniff
-- Enforce the use of a strict types declaration in PHP files
- Added PSR12.Classes.AnonClassDeclaration sniff
-- Enforces the formatting of anonymous classes
- Added PSR12.Classes.ClosingBrace sniff
-- Enforces that closing braces of classes/interfaces/traits/functions are not followed by a comment or statement
- Added PSR12.ControlStructures.BooleanOperatorPlacement sniff
Expand Down Expand Up @@ -1133,6 +1135,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
</dir>
<dir name="Sniffs">
<dir name="Classes">
<file baseinstalldir="PHP/CodeSniffer" name="AnonClassDeclarationSniff.php" role="php" />
<file baseinstalldir="PHP/CodeSniffer" name="ClassInstantiationSniff.php" role="php" />
<file baseinstalldir="PHP/CodeSniffer" name="ClosingBraceSniff.php" role="php" />
</dir>
Expand Down Expand Up @@ -1168,6 +1171,9 @@ http://pear.php.net/dtd/package-2.0.xsd">
</dir>
<dir name="Tests">
<dir name="Classes">
<file baseinstalldir="PHP/CodeSniffer" name="AnonClassDeclarationUnitTest.inc" role="test" />
<file baseinstalldir="PHP/CodeSniffer" name="AnonClassDeclarationUnitTest.inc.fixed" role="test" />
<file baseinstalldir="PHP/CodeSniffer" name="AnonClassDeclarationUnitTest.php" role="test" />
<file baseinstalldir="PHP/CodeSniffer" name="ClassInstantiationUnitTest.inc" role="test" />
<file baseinstalldir="PHP/CodeSniffer" name="ClassInstantiationUnitTest.inc.fixed" role="test" />
<file baseinstalldir="PHP/CodeSniffer" name="ClassInstantiationUnitTest.php" role="test" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,26 @@ public function process(File $phpcsFile, $stackPtr)
return;
}

$this->checkSpacing($phpcsFile, $stackPtr, $openBracket);

}//end process()


/**
* Checks the spacing around commas.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token in the
* stack passed in $tokens.
* @param int $openBracket The position of the opening bracket
* in the stack passed in $tokens.
*
* @return void
*/
public function checkSpacing(File $phpcsFile, $stackPtr, $openBracket)
{
$tokens = $phpcsFile->getTokens();

$closeBracket = $tokens[$openBracket]['parenthesis_closer'];
$nextSeparator = $openBracket;

Expand Down Expand Up @@ -117,7 +137,7 @@ public function process(File $phpcsFile, $stackPtr)
if ($tokens[($nextSeparator - 1)]['code'] === T_WHITESPACE) {
$prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($nextSeparator - 2), null, true);
if (isset(Tokens::$heredocTokens[$tokens[$prev]['code']]) === false) {
$error = 'Space found before comma in function call';
$error = 'Space found before comma in argument list';
$fix = $phpcsFile->addFixableError($error, $nextSeparator, 'SpaceBeforeComma');
if ($fix === true) {
$phpcsFile->fixer->beginChangeset();
Expand All @@ -135,7 +155,7 @@ public function process(File $phpcsFile, $stackPtr)
}//end if

if ($tokens[($nextSeparator + 1)]['code'] !== T_WHITESPACE) {
$error = 'No space found after comma in function call';
$error = 'No space found after comma in argument list';
$fix = $phpcsFile->addFixableError($error, $nextSeparator, 'NoSpaceAfterComma');
if ($fix === true) {
$phpcsFile->fixer->addContent($nextSeparator, ' ');
Expand All @@ -147,7 +167,7 @@ public function process(File $phpcsFile, $stackPtr)
if ($tokens[$next]['line'] === $tokens[$nextSeparator]['line']) {
$space = $tokens[($nextSeparator + 1)]['length'];
if ($space > 1) {
$error = 'Expected 1 space after comma in function call; %s found';
$error = 'Expected 1 space after comma in argument list; %s found';
$data = [$space];
$fix = $phpcsFile->addFixableError($error, $nextSeparator, 'TooMuchSpaceAfterComma', $data);
if ($fix === true) {
Expand All @@ -159,7 +179,7 @@ public function process(File $phpcsFile, $stackPtr)
}//end if
}//end while

}//end process()
}//end checkSpacing()


}//end class
Original file line number Diff line number Diff line change
Expand Up @@ -205,12 +205,12 @@ public function isMultiLineCall(File $phpcsFile, $stackPtr, $openBracket, $token
*/
public function processSingleLineCall(File $phpcsFile, $stackPtr, $openBracket, $tokens)
{
// If the function call has no arguments or comments, enforce 0 spaces.
$closer = $tokens[$openBracket]['parenthesis_closer'];
if ($openBracket === ($closer - 1)) {
return;
}

// If the function call has no arguments or comments, enforce 0 spaces.
$next = $phpcsFile->findNext(T_WHITESPACE, ($openBracket + 1), $closer, true);
if ($next === false) {
$requiredSpacesAfterOpen = 0;
Expand Down
188 changes: 109 additions & 79 deletions src/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,97 @@ public function processSingleLineDeclaration($phpcsFile, $stackPtr, $tokens)
*/
public function processMultiLineDeclaration($phpcsFile, $stackPtr, $tokens)
{
$this->processArgumentList($phpcsFile, $stackPtr, $this->indent);

$closeBracket = $tokens[$stackPtr]['parenthesis_closer'];
if ($tokens[$stackPtr]['code'] === T_CLOSURE) {
$use = $phpcsFile->findNext(T_USE, ($closeBracket + 1), $tokens[$stackPtr]['scope_opener']);
if ($use !== false) {
$open = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1));
$closeBracket = $tokens[$open]['parenthesis_closer'];
}
}

if (isset($tokens[$stackPtr]['scope_opener']) === false) {
return;
}

// The opening brace needs to be one space away from the closing parenthesis.
$opener = $tokens[$stackPtr]['scope_opener'];
if ($tokens[$opener]['line'] !== $tokens[$closeBracket]['line']) {
$error = 'The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line';
$fix = $phpcsFile->addFixableError($error, $opener, 'NewlineBeforeOpenBrace');
if ($fix === true) {
$prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($opener - 1), $closeBracket, true);
$phpcsFile->fixer->beginChangeset();
$phpcsFile->fixer->addContent($prev, ' {');

// If the opener is on a line by itself, removing it will create
// an empty line, so just remove the entire line instead.
$prev = $phpcsFile->findPrevious(T_WHITESPACE, ($opener - 1), $closeBracket, true);
$next = $phpcsFile->findNext(T_WHITESPACE, ($opener + 1), null, true);

if ($tokens[$prev]['line'] < $tokens[$opener]['line']
&& $tokens[$next]['line'] > $tokens[$opener]['line']
) {
// Clear the whole line.
for ($i = ($prev + 1); $i < $next; $i++) {
if ($tokens[$i]['line'] === $tokens[$opener]['line']) {
$phpcsFile->fixer->replaceToken($i, '');
}
}
} else {
// Just remove the opener.
$phpcsFile->fixer->replaceToken($opener, '');
if ($tokens[$next]['line'] === $tokens[$opener]['line']) {
$phpcsFile->fixer->replaceToken(($opener + 1), '');
}
}

$phpcsFile->fixer->endChangeset();
}//end if
} else {
$prev = $tokens[($opener - 1)];
if ($prev['code'] !== T_WHITESPACE) {
$length = 0;
} else {
$length = strlen($prev['content']);
}

if ($length !== 1) {
$error = 'There must be a single space between the closing parenthesis and the opening brace of a multi-line function declaration; found %s spaces';
$fix = $phpcsFile->addFixableError($error, ($opener - 1), 'SpaceBeforeOpenBrace', [$length]);
if ($fix === true) {
if ($length === 0) {
$phpcsFile->fixer->addContentBefore($opener, ' ');
} else {
$phpcsFile->fixer->replaceToken(($opener - 1), ' ');
}
}

return;
}//end if
}//end if

}//end processMultiLineDeclaration()


/**
* Processes multi-line argument list declarations.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
* @param int $indent The number of spaces code should be indented.
* @param string $type The type of the token the brackets
* belong to.
*
* @return void
*/
public function processArgumentList($phpcsFile, $stackPtr, $indent, $type='function')
{
$tokens = $phpcsFile->getTokens();

// We need to work out how far indented the function
// declaration itself is, so we can work out how far to
// indent parameters.
Expand Down Expand Up @@ -309,13 +400,13 @@ public function processMultiLineDeclaration($phpcsFile, $stackPtr, $tokens)
true
);

if ($tokens[$closeBracket]['line'] !== $tokens[$tokens[$closeBracket]['parenthesis_opener']]['line']) {
if ($tokens[$prev]['line'] === $tokens[$closeBracket]['line']) {
$error = 'The closing parenthesis of a multi-line function declaration must be on a new line';
$fix = $phpcsFile->addFixableError($error, $closeBracket, 'CloseBracketLine');
if ($fix === true) {
$phpcsFile->fixer->addNewlineBefore($closeBracket);
}
if ($tokens[$closeBracket]['line'] !== $tokens[$tokens[$closeBracket]['parenthesis_opener']]['line']
&& $tokens[$prev]['line'] === $tokens[$closeBracket]['line']
) {
$error = 'The closing parenthesis of a multi-line '.$type.' declaration must be on a new line';
$fix = $phpcsFile->addFixableError($error, $closeBracket, 'CloseBracketLine');
if ($fix === true) {
$phpcsFile->fixer->addNewlineBefore($closeBracket);
}
}

Expand All @@ -335,13 +426,13 @@ public function processMultiLineDeclaration($phpcsFile, $stackPtr, $tokens)
true
);

if ($tokens[$closeBracket]['line'] !== $tokens[$tokens[$closeBracket]['parenthesis_opener']]['line']) {
if ($tokens[$prev]['line'] === $tokens[$closeBracket]['line']) {
$error = 'The closing parenthesis of a multi-line use declaration must be on a new line';
$fix = $phpcsFile->addFixableError($error, $closeBracket, 'UseCloseBracketLine');
if ($fix === true) {
$phpcsFile->fixer->addNewlineBefore($closeBracket);
}
if ($tokens[$closeBracket]['line'] !== $tokens[$tokens[$closeBracket]['parenthesis_opener']]['line']
&& $tokens[$prev]['line'] === $tokens[$closeBracket]['line']
) {
$error = 'The closing parenthesis of a multi-line use declaration must be on a new line';
$fix = $phpcsFile->addFixableError($error, $closeBracket, 'UseCloseBracketLine');
if ($fix === true) {
$phpcsFile->fixer->addNewlineBefore($closeBracket);
}
}
}//end if
Expand All @@ -361,7 +452,7 @@ public function processMultiLineDeclaration($phpcsFile, $stackPtr, $tokens)
// as the function.
$expectedIndent = $functionIndent;
} else {
$expectedIndent = ($functionIndent + $this->indent);
$expectedIndent = ($functionIndent + $indent);
}

// We changed lines, so this should be a whitespace indent token.
Expand All @@ -371,7 +462,7 @@ public function processMultiLineDeclaration($phpcsFile, $stackPtr, $tokens)
// This is an empty line, so don't check the indent.
$foundIndent = $expectedIndent;

$error = 'Blank lines are not allowed in a multi-line function declaration';
$error = 'Blank lines are not allowed in a multi-line '.$type.' declaration';
$fix = $phpcsFile->addFixableError($error, $i, 'EmptyLine');
if ($fix === true) {
$phpcsFile->fixer->replaceToken($i, '');
Expand All @@ -381,7 +472,7 @@ public function processMultiLineDeclaration($phpcsFile, $stackPtr, $tokens)
}

if ($expectedIndent !== $foundIndent) {
$error = 'Multi-line function declaration not indented correctly; expected %s spaces but found %s';
$error = 'Multi-line '.$type.' declaration not indented correctly; expected %s spaces but found %s';
$data = [
$expectedIndent,
$foundIndent,
Expand Down Expand Up @@ -414,68 +505,7 @@ public function processMultiLineDeclaration($phpcsFile, $stackPtr, $tokens)
}
}//end for

if (isset($tokens[$stackPtr]['scope_opener']) === false) {
return;
}

// The opening brace needs to be one space away from the closing parenthesis.
$opener = $tokens[$stackPtr]['scope_opener'];
if ($tokens[$opener]['line'] !== $tokens[$closeBracket]['line']) {
$error = 'The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line';
$fix = $phpcsFile->addFixableError($error, $opener, 'NewlineBeforeOpenBrace');
if ($fix === true) {
$prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($opener - 1), $closeBracket, true);
$phpcsFile->fixer->beginChangeset();
$phpcsFile->fixer->addContent($prev, ' {');

// If the opener is on a line by itself, removing it will create
// an empty line, so just remove the entire line instead.
$prev = $phpcsFile->findPrevious(T_WHITESPACE, ($opener - 1), $closeBracket, true);
$next = $phpcsFile->findNext(T_WHITESPACE, ($opener + 1), null, true);

if ($tokens[$prev]['line'] < $tokens[$opener]['line']
&& $tokens[$next]['line'] > $tokens[$opener]['line']
) {
// Clear the whole line.
for ($i = ($prev + 1); $i < $next; $i++) {
if ($tokens[$i]['line'] === $tokens[$opener]['line']) {
$phpcsFile->fixer->replaceToken($i, '');
}
}
} else {
// Just remove the opener.
$phpcsFile->fixer->replaceToken($opener, '');
if ($tokens[$next]['line'] === $tokens[$opener]['line']) {
$phpcsFile->fixer->replaceToken(($opener + 1), '');
}
}

$phpcsFile->fixer->endChangeset();
}//end if
} else {
$prev = $tokens[($opener - 1)];
if ($prev['code'] !== T_WHITESPACE) {
$length = 0;
} else {
$length = strlen($prev['content']);
}

if ($length !== 1) {
$error = 'There must be a single space between the closing parenthesis and the opening brace of a multi-line function declaration; found %s spaces';
$fix = $phpcsFile->addFixableError($error, ($opener - 1), 'SpaceBeforeOpenBrace', [$length]);
if ($fix === true) {
if ($length === 0) {
$phpcsFile->fixer->addContentBefore($opener, ' ');
} else {
$phpcsFile->fixer->replaceToken(($opener - 1), ' ');
}
}

return;
}//end if
}//end if

}//end processMultiLineDeclaration()
}//end processArgumentList()


}//end class
Loading

0 comments on commit b770ed3

Please sign in to comment.