mirror of
https://github.com/10h30/genesis-simple-sidebars.git
synced 2026-07-19 06:23:25 +09:00
Introducing coding standards validation.
This commit is contained in:
committed by
Nathan Rice
parent
6e40c921ab
commit
fd504d41ac
Vendored
+235
@@ -0,0 +1,235 @@
|
||||
<?php
|
||||
/**
|
||||
* WordPress Coding Standard.
|
||||
*
|
||||
* @package WPCS\WordPressCodingStandards
|
||||
* @link https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace WordPress\Sniffs\CodeAnalysis;
|
||||
|
||||
use WordPress\Sniff;
|
||||
use PHP_CodeSniffer_Tokens as Tokens;
|
||||
|
||||
/**
|
||||
* Detects variable assignments being made within conditions.
|
||||
*
|
||||
* This is a typical code smell and more often than not a comparison was intended.
|
||||
*
|
||||
* Note: this sniff does not detect variable assignments in ternaries without parentheses!
|
||||
*
|
||||
* @package WPCS\WordPressCodingStandards
|
||||
*
|
||||
* @since 0.14.0
|
||||
*
|
||||
* {@internal This sniff is a duplicate of the same sniff as pulled upstream.
|
||||
* Once the upstream sniff has been merged and the minimum WPCS PHPCS requirement has gone up to
|
||||
* the version in which the sniff was merged, this version can be safely removed.
|
||||
* {@link https://github.com/squizlabs/PHP_CodeSniffer/pull/1594} }}
|
||||
*/
|
||||
class AssignmentInConditionSniff extends Sniff {
|
||||
|
||||
/**
|
||||
* Assignment tokens to trigger on.
|
||||
*
|
||||
* Set in the register() method.
|
||||
*
|
||||
* @since 0.14.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $assignment_tokens = array();
|
||||
|
||||
/**
|
||||
* The tokens that indicate the start of a condition.
|
||||
*
|
||||
* @since 0.14.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $condition_start_tokens = array();
|
||||
|
||||
/**
|
||||
* Registers the tokens that this sniff wants to listen for.
|
||||
*
|
||||
* @since 0.14.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register() {
|
||||
$this->assignment_tokens = Tokens::$assignmentTokens;
|
||||
unset( $this->assignment_tokens[ \T_DOUBLE_ARROW ] );
|
||||
|
||||
$starters = Tokens::$booleanOperators;
|
||||
$starters[ \T_SEMICOLON ] = \T_SEMICOLON;
|
||||
$starters[ \T_OPEN_PARENTHESIS ] = \T_OPEN_PARENTHESIS;
|
||||
$starters[ \T_INLINE_ELSE ] = \T_INLINE_ELSE;
|
||||
|
||||
$this->condition_start_tokens = $starters;
|
||||
|
||||
return array(
|
||||
\T_IF,
|
||||
\T_ELSEIF,
|
||||
\T_FOR,
|
||||
\T_SWITCH,
|
||||
\T_CASE,
|
||||
\T_WHILE,
|
||||
\T_INLINE_THEN,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes this test, when one of its tokens is encountered.
|
||||
*
|
||||
* @since 0.14.0
|
||||
*
|
||||
* @param int $stackPtr The position of the current token in the stack.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process_token( $stackPtr ) {
|
||||
|
||||
$token = $this->tokens[ $stackPtr ];
|
||||
|
||||
// Find the condition opener/closer.
|
||||
if ( \T_FOR === $token['code'] ) {
|
||||
if ( isset( $token['parenthesis_opener'], $token['parenthesis_closer'] ) === false ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$semicolon = $this->phpcsFile->findNext( \T_SEMICOLON, ( $token['parenthesis_opener'] + 1 ), $token['parenthesis_closer'] );
|
||||
if ( false === $semicolon ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$opener = $semicolon;
|
||||
$semicolon = $this->phpcsFile->findNext( \T_SEMICOLON, ( $opener + 1 ), $token['parenthesis_closer'] );
|
||||
if ( false === $semicolon ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$closer = $semicolon;
|
||||
unset( $semicolon );
|
||||
|
||||
} elseif ( \T_CASE === $token['code'] ) {
|
||||
if ( isset( $token['scope_opener'] ) === false ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$opener = $stackPtr;
|
||||
$closer = $token['scope_opener'];
|
||||
|
||||
} elseif ( \T_INLINE_THEN === $token['code'] ) {
|
||||
// Check if the condition for the ternary is bracketed.
|
||||
$prev = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, ( $stackPtr - 1 ), null, true );
|
||||
if ( false === $prev ) {
|
||||
// Shouldn't happen, but in that case we don't have anything to examine anyway.
|
||||
return;
|
||||
}
|
||||
|
||||
if ( \T_CLOSE_PARENTHESIS === $this->tokens[ $prev ]['code'] ) {
|
||||
if ( ! isset( $this->tokens[ $prev ]['parenthesis_opener'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$opener = $this->tokens[ $prev ]['parenthesis_opener'];
|
||||
$closer = $prev;
|
||||
} elseif ( isset( $token['nested_parenthesis'] ) ) {
|
||||
$closer = end( $token['nested_parenthesis'] );
|
||||
$opener = key( $token['nested_parenthesis'] );
|
||||
|
||||
$next_statement_closer = $this->phpcsFile->findEndOfStatement( $stackPtr, array( \T_COLON, \T_CLOSE_PARENTHESIS, \T_CLOSE_SQUARE_BRACKET ) );
|
||||
if ( false !== $next_statement_closer && $next_statement_closer < $closer ) {
|
||||
// Parentheses are unrelated to the ternary.
|
||||
return;
|
||||
}
|
||||
|
||||
$prev_statement_closer = $this->phpcsFile->findStartOfStatement( $stackPtr, array( \T_COLON, \T_OPEN_PARENTHESIS, \T_OPEN_SQUARE_BRACKET ) );
|
||||
if ( false !== $prev_statement_closer && $opener < $prev_statement_closer ) {
|
||||
// Parentheses are unrelated to the ternary.
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $closer > $stackPtr ) {
|
||||
$closer = $stackPtr;
|
||||
}
|
||||
} else {
|
||||
// No parenthesis found, can't determine where the conditional part of the ternary starts.
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if ( isset( $token['parenthesis_opener'], $token['parenthesis_closer'] ) === false ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$opener = $token['parenthesis_opener'];
|
||||
$closer = $token['parenthesis_closer'];
|
||||
}
|
||||
|
||||
$startPos = $opener;
|
||||
|
||||
do {
|
||||
$hasAssignment = $this->phpcsFile->findNext( $this->assignment_tokens, ( $startPos + 1 ), $closer );
|
||||
if ( false === $hasAssignment ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Examine whether the left side is a variable.
|
||||
$hasVariable = false;
|
||||
$conditionStart = $startPos;
|
||||
$altConditionStart = $this->phpcsFile->findPrevious(
|
||||
$this->condition_start_tokens,
|
||||
( $hasAssignment - 1 ),
|
||||
$startPos
|
||||
);
|
||||
if ( false !== $altConditionStart ) {
|
||||
$conditionStart = $altConditionStart;
|
||||
}
|
||||
|
||||
for ( $i = $hasAssignment; $i > $conditionStart; $i-- ) {
|
||||
if ( isset( Tokens::$emptyTokens[ $this->tokens[ $i ]['code'] ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this is a variable or array, we've seen all we need to see.
|
||||
if ( \T_VARIABLE === $this->tokens[ $i ]['code']
|
||||
|| \T_CLOSE_SQUARE_BRACKET === $this->tokens[ $i ]['code']
|
||||
) {
|
||||
$hasVariable = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// If this is a function call or something, we are OK.
|
||||
if ( \T_CLOSE_PARENTHESIS === $this->tokens[ $i ]['code'] ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( true === $hasVariable ) {
|
||||
$errorCode = 'Found';
|
||||
if ( \T_WHILE === $token['code'] ) {
|
||||
$errorCode = 'FoundInWhileCondition';
|
||||
} elseif ( \T_INLINE_THEN === $token['code'] ) {
|
||||
$errorCode = 'FoundInTernaryCondition';
|
||||
}
|
||||
|
||||
$this->phpcsFile->addWarning(
|
||||
'Variable assignment found within a condition. Did you mean to do a comparison?',
|
||||
$hasAssignment,
|
||||
$errorCode
|
||||
);
|
||||
} else {
|
||||
$this->phpcsFile->addWarning(
|
||||
'Assignment found within a condition. Did you mean to do a comparison?',
|
||||
$hasAssignment,
|
||||
'NonVariableAssignmentFound'
|
||||
);
|
||||
}
|
||||
|
||||
$startPos = $hasAssignment;
|
||||
|
||||
} while ( $startPos < $closer );
|
||||
}
|
||||
|
||||
}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
/**
|
||||
* WordPress Coding Standard.
|
||||
*
|
||||
* @package WPCS\WordPressCodingStandards
|
||||
* @link https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
namespace WordPress\Sniffs\CodeAnalysis;
|
||||
|
||||
use WordPress\Sniff;
|
||||
use PHP_CodeSniffer_Tokens as Tokens;
|
||||
|
||||
/**
|
||||
* Checks against empty statements.
|
||||
*
|
||||
* - Check against two semi-colons with no executable code in between.
|
||||
* - Check against an empty PHP open - close tag combination.
|
||||
*
|
||||
* {@internal This check should at some point in the future be pulled upstream and probably
|
||||
* merged into the upstream `Generic.CodeAnalysis.EmptyStatement` sniff.
|
||||
* This will need to wait until the WPCS minimum requirements have gone up
|
||||
* beyond PHPCS 3.x though as it is not likely that new features will be accepted
|
||||
* still for the PHPCS 2.x branch.}}
|
||||
*
|
||||
* @package WPCS\WordPressCodingStandards
|
||||
*
|
||||
* @since 0.12.0
|
||||
* @since 0.13.0 Class name changed: this class is now namespaced.
|
||||
*/
|
||||
class EmptyStatementSniff extends Sniff {
|
||||
|
||||
/**
|
||||
* Returns an array of tokens this test wants to listen for.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register() {
|
||||
return array(
|
||||
\T_SEMICOLON,
|
||||
\T_CLOSE_TAG,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes this test, when one of its tokens is encountered.
|
||||
*
|
||||
* @param int $stackPtr The position of the current token in the stack.
|
||||
*
|
||||
* @return int Integer stack pointer to skip the rest of the file.
|
||||
*/
|
||||
public function process_token( $stackPtr ) {
|
||||
|
||||
switch ( $this->tokens[ $stackPtr ]['type'] ) {
|
||||
/*
|
||||
* Detect `something();;`.
|
||||
*/
|
||||
case 'T_SEMICOLON':
|
||||
$prevNonEmpty = $this->phpcsFile->findPrevious(
|
||||
Tokens::$emptyTokens,
|
||||
( $stackPtr - 1 ),
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
||||
if ( false === $prevNonEmpty
|
||||
|| ( \T_SEMICOLON !== $this->tokens[ $prevNonEmpty ]['code']
|
||||
&& \T_OPEN_TAG !== $this->tokens[ $prevNonEmpty ]['code']
|
||||
&& \T_OPEN_TAG_WITH_ECHO !== $this->tokens[ $prevNonEmpty ]['code'] )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( isset( $this->tokens[ $stackPtr ]['nested_parenthesis'] ) ) {
|
||||
$nested = $this->tokens[ $stackPtr ]['nested_parenthesis'];
|
||||
$last_closer = array_pop( $nested );
|
||||
if ( isset( $this->tokens[ $last_closer ]['parenthesis_owner'] )
|
||||
&& \T_FOR === $this->tokens[ $this->tokens[ $last_closer ]['parenthesis_owner'] ]['code']
|
||||
) {
|
||||
// Empty for() condition.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$fix = $this->phpcsFile->addFixableWarning(
|
||||
'Empty PHP statement detected: superfluous semi-colon.',
|
||||
$stackPtr,
|
||||
'SemicolonWithoutCodeDetected'
|
||||
);
|
||||
if ( true === $fix ) {
|
||||
$this->phpcsFile->fixer->beginChangeset();
|
||||
|
||||
if ( \T_OPEN_TAG === $this->tokens[ $prevNonEmpty ]['code']
|
||||
|| \T_OPEN_TAG_WITH_ECHO === $this->tokens[ $prevNonEmpty ]['code']
|
||||
) {
|
||||
/*
|
||||
* Check for superfluous whitespace after the semi-colon which will be
|
||||
* removed as the `<?php ` open tag token already contains whitespace,
|
||||
* either a space or a new line and in case of a new line, the indentation
|
||||
* should be done via tabs, so spaces can be safely removed.
|
||||
*/
|
||||
if ( \T_WHITESPACE === $this->tokens[ ( $stackPtr + 1 ) ]['code'] ) {
|
||||
$replacement = str_replace( ' ', '', $this->tokens[ ( $stackPtr + 1 ) ]['content'] );
|
||||
$this->phpcsFile->fixer->replaceToken( ( $stackPtr + 1 ), $replacement );
|
||||
}
|
||||
}
|
||||
|
||||
for ( $i = $stackPtr; $i > $prevNonEmpty; $i-- ) {
|
||||
if ( \T_SEMICOLON !== $this->tokens[ $i ]['code']
|
||||
&& \T_WHITESPACE !== $this->tokens[ $i ]['code']
|
||||
) {
|
||||
break;
|
||||
}
|
||||
$this->phpcsFile->fixer->replaceToken( $i, '' );
|
||||
}
|
||||
|
||||
$this->phpcsFile->fixer->endChangeset();
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
* Detect `<?php ?>`.
|
||||
*/
|
||||
case 'T_CLOSE_TAG':
|
||||
$prevNonEmpty = $this->phpcsFile->findPrevious(
|
||||
\T_WHITESPACE,
|
||||
( $stackPtr - 1 ),
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
||||
if ( false === $prevNonEmpty
|
||||
|| ( \T_OPEN_TAG !== $this->tokens[ $prevNonEmpty ]['code']
|
||||
&& \T_OPEN_TAG_WITH_ECHO !== $this->tokens[ $prevNonEmpty ]['code'] )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fix = $this->phpcsFile->addFixableWarning(
|
||||
'Empty PHP open/close tag combination detected.',
|
||||
$prevNonEmpty,
|
||||
'EmptyPHPOpenCloseTagsDetected'
|
||||
);
|
||||
if ( true === $fix ) {
|
||||
$this->phpcsFile->fixer->beginChangeset();
|
||||
for ( $i = $prevNonEmpty; $i <= $stackPtr; $i++ ) {
|
||||
$this->phpcsFile->fixer->replaceToken( $i, '' );
|
||||
}
|
||||
$this->phpcsFile->fixer->endChangeset();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Deliberately left empty. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user